예제 #1
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));
            }
        }
예제 #2
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]);
        }