예제 #1
0
        internal static ForeignKeyInfo Create(System.Reflection.PropertyInfo theProperty)
        {
            if (theProperty == null)
            {
                return(null);
            }
            ForeignKeyInfo fk = new ForeignKeyInfo();

            fk._RelatedProperty = theProperty;

            fk.fieldAttributes = (ForeignKeyFieldAttribute[])(fk.RelatedProperty.GetCustomAttributes(typeof(ForeignKeyFieldAttribute), true));

            ForeignKeyAttribute[] fkAttribs = (ForeignKeyAttribute[])(fk.RelatedProperty.GetCustomAttributes(typeof(ForeignKeyAttribute), true));

            if (fk.fieldAttributes.Length == 0)
            {
                return(null);
            }
            else
            {
                if (fkAttribs.Length == 0)
                {
                    fk.foreignKeyDefinition = new ForeignKeyAttribute();
                }
                else
                {
                    fk.foreignKeyDefinition = fkAttribs[0];
                }
                return(fk);
            }
        }
예제 #2
0
        /// <summary>
        /// Sets the LocalTableInfo and ForeignTableInfo of all joins recursivelly.
        /// </summary>
        /// <param name="list"></param>
        /// <param name="join"></param>
        /// <param name="baseClass"></param>
        private static void SetProperty(List <Join> list, Join join, Type baseClass)
        {
            if (join.LocalTableInfo == null)
            {
                if (string.IsNullOrEmpty(join.ParentAlias))
                {
                    join.LocalTableInfo = TableInfo.CreateTableInfo(baseClass);
                }
                else
                {
                    int pos = list.IndexOf(new Join(join.ParentAlias));
                    if (pos == -1)
                    {
                        throw new InvalidOperationException("Cannot find the parent alias for '" + join.JoinAlias + "'");
                    }
                    Join parent = list[pos];
                    if (parent.LocalTableInfo == null)
                    {
                        SetProperty(list, parent, baseClass);
                    }

                    join.LocalTableInfo = TableInfo.CreateTableInfo(parent.ForeignKey.ElementType);
                }
            }

            join.ForeignKey = ForeignKeyInfo.Create(join.LocalTableInfo.RelatedTable.GetProperty(join.PropertyName));
            if (join.ForeignKey == null)
            {
                throw new InvalidOperationException("Cannot find '" + join.PropertyName + "' on '" + join.LocalTableInfo.RelatedTable.Name + "' class. You must define a ForeignKey on that class.");
            }
            join.ForeignTableInfo = TableInfo.CreateTableInfo(join.ForeignKey.ElementType);
        }
예제 #3
0
        /// <summary>
        /// </summary>
        internal static ForeignKeyInfo[] GetForeignKeys(Type instanceType)
        {
            List <ForeignKeyInfo> res = new List <ForeignKeyInfo>();

            foreach (System.Reflection.PropertyInfo i in instanceType.GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic))
            {
                ForeignKeyInfo foreign = ForeignKeyInfo.Create(i);
                if (foreign != null)
                {
                    res.Add(foreign);
                }
            }
            return(res.ToArray());
        }
예제 #4
0
        /// <summary>
        /// Includes the property on the eager loading list.
        /// </summary>
        /// <param name="foreignPropertyName">The name of the property on the base class of this SearchOptions.</param>
        public void LoadAlso(string foreignPropertyName)
        {
            if (string.IsNullOrEmpty(foreignPropertyName))
            {
                throw new ArgumentNullException("foreignPropertyName");
            }

            ForeignKeyInfo fkInfo = ForeignKeyInfo.Create(baseType.GetProperty(foreignPropertyName));

            if (fkInfo == null)
            {
                throw new MissingForeignKeyException(baseType, foreignPropertyName);
            }

            //TODO: Find a better alias name.
            string alias = foreignPropertyName;

            eagerLoading.Add(fkInfo, alias);
        }
예제 #5
0
        protected void Init(EntityBase Parent, string RelatedPropertyName, Type RelatedPropertyType)
        {
            _Parent = Parent;

            System.Reflection.PropertyInfo prop;
            if (RelatedPropertyType != null)
            {
                prop = Parent.GetType().GetProperty(RelatedPropertyName, RelatedPropertyType);
            }
            else
            {
                prop = Parent.GetType().GetProperty(RelatedPropertyName);
            }
            ForeignKey = ForeignKeyInfo.Create(prop);
            if (ForeignKey == null)
            {
                throw new MissingForeignKeyException(prop.DeclaringType, prop.Name);
            }

            list = new List <T>();
        }
예제 #6
0
        /// <summary>
        /// Persists a list on the database.
        /// </summary>
        /// <param name="propertyName">The name of a many-to-many property on this class.</param>
        public virtual void SaveList(string propertyName)
        {
            if (propertyName == null)
            {
                throw new ArgumentNullException("propertyName");
            }
            System.Reflection.PropertyInfo prop = this.GetType().GetProperty(propertyName);
            if (prop == null)
            {
                throw new ArgumentException(string.Format("The property '{0}' was not found on '{1}'.", propertyName, this.GetType().FullName), "propertyName");
            }
            ForeignKeyInfo fkInfo = ForeignKeyInfo.Create(prop);

            if (fkInfo == null)
            {
                throw new InvalidMappingException(this.GetType());
            }

            if (!fkInfo.IsManyToMany)
            {
                throw new TenorException("Currently, only many-to-many relations are supported");
            }


            TableInfo table = TableInfo.CreateTableInfo(this.GetType());

            if (table == null)
            {
                throw new InvalidMappingException(this.GetType());
            }

            ConnectionStringSettings connection = (tenorTransaction == null ? table.GetConnection() : tenorTransaction.Connection);
            GeneralDialect           dialect    = DialectFactory.CreateDialect(connection);

            TenorParameter[] parameters;
            DbTransaction    t = (tenorTransaction == null ? null : tenorTransaction.dbTransaction);

            //if (dialect.GetType() == typeof(Tenor.Data.Dialects.TSql.TSql))
            //{
            //    //oh god! do you have a better idea on where to write this code?
            //    System.Data.SqlClient.SqlBulkCopy bulk;
            //    if (t == null)
            //        bulk = new System.Data.SqlClient.SqlBulkCopy(tenorTransaction.Connection.ConnectionString);
            //    else
            //        bulk = new System.Data.SqlClient.SqlBulkCopy((System.Data.SqlClient.SqlConnection)t.Connection, System.Data.SqlClient.SqlBulkCopyOptions.Default, (System.Data.SqlClient.SqlTransaction)t);

            //    bulk.DestinationTableName = dialect.GetPrefixAndTable(fkInfo.ManyToManyTablePrefix, fkInfo.ManyToManyTable);
            //    System.Data.DataTable data;
            //    string sql = dialect.CreateSaveList(table, fkInfo, this, out parameters, out data);
            //    foreach (DataColumn col in data.Columns)
            //    {
            //        bulk.ColumnMappings.Add(col.ColumnName, col.ColumnName);
            //    }

            //    Helper.ExecuteQuery(sql, parameters, t, dialect);
            //    bulk.WriteToServer(data);
            //    bulk.Close();
            //}
            //else
            //{
            string sql = dialect.CreateSaveListSql(table, fkInfo, this, out parameters);

            Helper.ExecuteQuery(sql, parameters, t, dialect);
            //}
        }
예제 #7
0
        /// <summary>
        /// Converts a datatable into a set of instances of baseClass.
        /// </summary>
        /// <param name="table">A System.Data.DataTable with raw database data.</param>
        /// <param name="lazyLoading">Indicates whether to enable the lazyLoading on created instances.</param>
        /// <param name="baseClass">Defines which type to load.</param>
        /// <exception cref="System.ArgumentNullException">Occurs when table or baseClass parameters are null.</exception>
        /// <returns>An array of entities.</returns>
        internal static EntityBase[] BindRows(DataTable table, SearchOptions searchOptions, string baseAlias)
        {
            if (table == null)
            {
                throw new ArgumentNullException("table");
            }
            if (searchOptions == null)
            {
                throw new ArgumentNullException("searchOptions");
            }
            if (searchOptions.eagerLoading.Count == 0)
            {
                //TODO: Check if this is necessary by performance needs.
                EntityBase[] instances = (EntityBase[])(Array.CreateInstance(searchOptions.baseType, table.Rows.Count));
                for (int i = 0; i <= instances.Length - 1; i++)
                {
                    instances[i] = (EntityBase)(Activator.CreateInstance(searchOptions.baseType));
                    instances[i].Bind(searchOptions.LazyLoading, baseAlias, null, table.Rows[i]);
                }
                return(instances);
            }
            else
            {
                Type  listof    = typeof(List <>).MakeGenericType(searchOptions.baseType);
                IList instances = (IList)Activator.CreateInstance(listof);
                //lets get metadata for baseClass and other things requested by the user.

                List <FieldInfo[]> meta = new List <FieldInfo[]>();
                meta.Add(EntityBase.GetPrimaryKeys(searchOptions.baseType));

                List <ForeignKeyInfo> keys = new List <ForeignKeyInfo>(); //i need this to get fks by index
                foreach (ForeignKeyInfo fkInfo in searchOptions.eagerLoading.Keys)
                {
                    keys.Add(fkInfo);
                    meta.Add(EntityBase.GetPrimaryKeys(fkInfo.ElementType)); //pks of each eagerloading
                }

                List <string>[] lastPk = new List <string> [meta.Count];
                for (int i = 0; i < meta.Count; i++)
                {
                    lastPk[i] = new List <string>();
                }

                foreach (DataRow dr in table.Rows)
                {
                    string basePk = string.Empty;
                    foreach (FieldInfo fi in meta[0])
                    {
                        string alias = fi.DataFieldName;
                        basePk += "||" + dr[alias].ToString();
                    }

                    for (int i = 0; i < meta.Count; i++)
                    {
                        ForeignKeyInfo key = (i == 0 ? null : keys[i - 1]);

                        string currentPKs = basePk;
                        if (i > 0)
                        {
                            foreach (FieldInfo fi in meta[i])
                            {
                                string alias = (i == 0 ? fi.DataFieldName : searchOptions.eagerLoading[key] + fi.DataFieldName);
                                currentPKs += "||" + dr[alias].ToString();
                            }
                        }

                        if (!string.IsNullOrEmpty(currentPKs) && !lastPk[i].Contains(currentPKs))
                        {
                            lastPk[i].Add(currentPKs);
                            EntityBase instance = (EntityBase)Activator.CreateInstance((i == 0 ? searchOptions.baseType : key.ElementType));
                            instance.Bind(searchOptions.LazyLoading, (i == 0 ? null : searchOptions.eagerLoading[key]), null, dr);

                            if (key == null)
                            {
                                instances.Add(instance);
                            }
                            else
                            {
                                int        index        = lastPk[0].IndexOf(basePk);
                                EntityBase baseInstance = (EntityBase)instances[index];
                                if (key.IsArray)
                                {
                                    baseInstance.lazyEnabled = false;
                                    IList value = (IList)baseInstance.GetPropertyValue(key.RelatedProperty.Name, false);
                                    baseInstance.lazyEnabled = true;
                                    value.Add(instance);
                                }
                                else
                                {
                                    baseInstance.SetPropertyValue(key.RelatedProperty.Name, instance);
                                }
                            }
                        }
                    }
                }

                return((EntityBase[])instances.GetType().GetMethod("ToArray").Invoke(instances, null));
            }
        }
예제 #8
0
        /// <summary>
        /// Loads a foreign key property.
        /// </summary>
        /// <param name="property">The property.</param>
        /// <param name="connection">The connection.</param>
        /// <remarks></remarks>
        internal object LoadForeign(System.Reflection.PropertyInfo property, ConnectionStringSettings connection)
        {
            if (!propertyData.ContainsKey(property.Name))
            {
                ForeignKeyInfo field = ForeignKeyInfo.Create(property);
                if (field == null)
                {
                    throw new Tenor.Data.MissingFieldException(property.DeclaringType, property.Name);
                }

                /*
                 * Dim filters As String = ""
                 * Dim params As New List(Of Data.Parameter)
                 */
                TableInfo table = TableInfo.CreateTableInfo(field.ElementType);
                if (connection == null)
                {
                    connection = table.GetConnection();
                }


                if (!field.IsArray && table.Cacheable)
                {
                    //We found a cacheble instance, so we don't need to search.
                    EntityBase instance = (EntityBase)Activator.CreateInstance(table.RelatedTable);
                    for (int i = 0; i <= field.ForeignFields.Length - 1; i++)
                    {
                        field.ForeignFields[i].SetPropertyValue(instance, field.LocalFields[i].PropertyValue(this));
                    }
                    instance.Bind();
                    field.SetPropertyValue(this, instance);
                    return(instance);
                }

                EntityBase[] instances;
                if (lazyEnabled)
                {
                    SearchOptions sc = new SearchOptions(field.ElementType);

                    bool fkHasValue = false;

                    if (field.IsManyToMany)
                    {
                        Join j = new Join(GeneralDialect.ManyToManyAlias);
                        j.ForeignKey     = field;
                        j.LocalTableInfo = table;
                        sc.Conditions.includes.Add(j);

                        for (int i = 0; i <= field.ForeignFields.Length - 1; i++)
                        {
                            if (i > 0)
                            {
                                sc.Conditions.Add(Tenor.Data.LogicalOperator.And);
                            }
                            SearchConditionForManyToMany scmm = new SearchConditionForManyToMany(
                                GeneralDialect.ManyToManyAlias,
                                field.LocalManyToManyFields[i],
                                field.LocalFields[i].PropertyValue(this));

                            sc.Conditions.Add(scmm);

                            fkHasValue = true;
                        }
                    }
                    else
                    {
                        //lets find objects, one-to-many and many-to-one
                        //for each Foreign, join an AND operator to match foreign with local value.

                        if (field.ForeignFields.Length != field.LocalFields.Length)
                        {
                            throw new MissingForeignKeyException(this.GetType(), property.Name);
                        }

                        for (int i = 0; i <= field.ForeignFields.Length - 1; i++)
                        {
                            if (i > 0)
                            {
                                sc.Conditions.Add(Tenor.Data.LogicalOperator.And);
                            }

                            object value = field.LocalFields[i].PropertyValue(this);

                            // only one fk field needs to have a value set
                            fkHasValue = fkHasValue || (value != null && value != DBNull.Value);

                            sc.Conditions.Add(
                                /* the foreign property name */
                                field.ForeignFields[i].RelatedProperty.Name,
                                /* the local value */
                                value);
                        }

                        if (sc.Conditions.Count == 0)
                        {
                            //this should never happen.
                            throw (new TenorException());
                        }
                    }

                    // lazy is enabled, go database, go!

                    // only searches if fk field is not null
                    if (fkHasValue)
                    {
                        instances = sc.Execute(connection);
                    }
                    else
                    {
                        instances = new EntityBase[] { }
                    };
                }
                else
                {
                    //lazy is disabled, so, no data will be retrieved.
                    instances = new EntityBase[] { };
                }


                if (field.IsArray)
                {
                    if (field.RelatedProperty.PropertyType.IsArray)
                    {
                        propertyData.Add(property.Name, instances);
                    }
                    else
                    {
                        // There must be another way to create it, string is not cool.
                        Type listof = Type.GetType("Tenor.Data.EntityList`1[[" + field.ElementType.AssemblyQualifiedName + "]]");
                        System.Reflection.ConstructorInfo ctor = listof.GetConstructor(System.Reflection.BindingFlags.CreateInstance | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic, null, new Type[] { typeof(EntityBase), typeof(string) }, null);
                        IList obj = (IList)ctor.Invoke(new object[] { (EntityBase)this, property.Name });
                        obj.Clear();
                        foreach (EntityBase i in instances)
                        {
                            obj.Add(i);
                        }
                        propertyData.Add(property.Name, obj);
                    }
                }
                else
                {
                    if (instances.Length == 0)
                    {
                        propertyData.Add(property.Name, null);
                    }
                    else
                    {
                        if (instances.Length > 1)
                        {
                            throw new ManyRecordsFoundException();//"LoadingForeignKey-ManyToOne: More than one instance was returned");
                        }
                        propertyData.Add(property.Name, instances[0]);
                    }
                }
            }
            return(propertyData[property.Name]);
        }
예제 #9
0
        /// <summary>
        /// Gets the value of a lazy tagged property.
        /// This call can do a database access.
        /// </summary>
        internal virtual object GetPropertyValue(string propertyName, bool forceGetBinary)
        {
            //only loads if not loaded yet.
            //TODO: provide a way to reload from database.
            lock (propertyData)
            {
                if (forceGetBinary || !propertyData.ContainsKey(propertyName))
                {
                    //Getting class metadata.

                    TableInfo table = TableInfo.CreateTableInfo(this.GetType());

                    System.Reflection.PropertyInfo fieldP = this.GetType().GetProperty(propertyName);
                    if (fieldP == null)
                    {
                        throw new Tenor.Data.MissingFieldException(this.GetType(), propertyName);
                    }

                    ForeignKeyInfo fkInfo = null;

                    fkInfo = ForeignKeyInfo.Create(fieldP);

                    if (fkInfo != null)
                    {
                        // this is an FK, so, route to fk loading
                        return(LoadForeign(fieldP, null));
                    }
                    else
                    {
                        //Continue to the lazy property (lazy fields like byte[]) loading
                        FieldInfo field = FieldInfo.Create(fieldP);
                        if (field == null)
                        {
                            throw new Tenor.Data.MissingFieldException(this.GetType(), fieldP.Name);
                        }

                        if (!forceGetBinary && (field.FieldType == typeof(BinaryStream) || field.FieldType == typeof(BinaryStream).BaseType))
                        {
                            propertyData[propertyName] = new BinaryStream(this, propertyName);
                        }
                        else
                        {
                            GeneralDialect dialect = DialectFactory.CreateDialect(table.GetConnection());


                            ConditionCollection conditions = new ConditionCollection();

                            foreach (FieldInfo f in GetFields(this.GetType(), true))
                            {
                                conditions.Add(f.RelatedProperty.Name, f.PropertyValue(this));
                            }
                            if (conditions.Count == 0)
                            {
                                throw (new Tenor.Data.MissingPrimaryKeyException(this.GetType()));
                            }

                            TenorParameter[] parameters = null;
                            string           fieldsPart = dialect.CreateSelectSql(table.RelatedTable, null, new FieldInfo[] { field }, null, null);
                            string           wherePart  = dialect.CreateWhereSql(conditions, table.RelatedTable, null, out parameters);
                            string           sql        = dialect.CreateFullSql(table.RelatedTable,
                                                                                false, false,
                                                                                0, fieldsPart, null, null, wherePart);

                            Tenor.Diagnostics.Debug.DebugSQL("GetPropertyValue()", sql, parameters, table.GetConnection());
#if DEBUG
                            LastSearches.Push(sql);
#endif
                            Tenor.Data.DataTable rs = new Tenor.Data.DataTable(sql, parameters, table.GetConnection());
                            rs.Bind();

                            if (rs.Rows.Count == 0)
                            {
                                throw (new RecordNotFoundException());
                            }
                            else if (rs.Rows.Count > 1)
                            {
                                throw new ManyRecordsFoundException();
                            }
                            else
                            {
                                var obj = rs.Rows[0][field.DataFieldName];
                                if (obj == DBNull.Value)
                                {
                                    obj = null;
                                }

                                if (forceGetBinary)
                                {
                                    if (obj == null)
                                    {
                                        return new byte[] { }
                                    }
                                    ;
                                    else
                                    {
                                        return(obj);
                                    }
                                }
                                else
                                {
                                    propertyData[propertyName] = obj;
                                }
                            }
                        }
                    }
                }
                return(propertyData[propertyName]);
            }
        }