/// <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]); }