diff --git a/Database/DatabaseObjectsUsingAttributesHelper.cs b/Database/DatabaseObjectsUsingAttributesHelper.cs index 18231b7..b003359 100644 --- a/Database/DatabaseObjectsUsingAttributesHelper.cs +++ b/Database/DatabaseObjectsUsingAttributesHelper.cs @@ -190,7 +190,7 @@ public SQL.SQLSelectTableJoins TableJoins(SQL.SQLSelectTable objPrimaryTable, SQ else { //If the ObjectReferenceEarlyBindingAttribute is specified on the item instance then create the table joins that will be required - var earlyBindingTableJoins = ObjectReferenceEarlyBinding.GetTableJoins(pobjDatabaseObjects, objPrimaryTable, this.GetItemInstanceType()); + var earlyBindingTableJoins = ObjectReferenceEarlyBinding.GetTableJoins(objPrimaryTable, this.GetItemInstanceType()); if (earlyBindingTableJoins.Count > 0) tableJoinsCollection = earlyBindingTableJoins; diff --git a/Database/ObjectReferenceEarlyBinding.cs b/Database/ObjectReferenceEarlyBinding.cs index e2b17a1..0623805 100644 --- a/Database/ObjectReferenceEarlyBinding.cs +++ b/Database/ObjectReferenceEarlyBinding.cs @@ -131,12 +131,26 @@ private class CollectionType /// /// Returns an empty list if there are no early binding required for the item instance type, otherwise the table joins required. private static CollectionTypesInAssemblies collectionTypesInAssemblies = new CollectionTypesInAssemblies(); - - internal static SQL.SQLSelectTableJoins GetTableJoins(IDatabaseObjects collection, SQL.SQLSelectTable collectionTable, Type itemInstanceType) + + internal static SQL.SQLSelectTableJoins GetTableJoins(SQL.SQLSelectTable collectionTable, Type itemInstanceType) + { + var tableJoins = new SQL.SQLSelectTableJoins(); + + GetTableJoins(collectionTable, itemInstanceType, collectionTable, tableJoins); + + return tableJoins; + } + + /// + /// Creates all of the table joins by traversing the item instance type and finding ObjectReferenceEarlyBinding and FieldMapping attributed fields + /// and then finding the corresponding item instance type and the associated collection / table that it should be joined to. + /// This applies to all of the fields in the item instance type and also to any other table joins that the fields refer to. + /// Essentially, ensuring that all table joins are created for the collection. + /// + /// The joined table which contains all of the calculated table joins + /// The joined table which contains all of the calculated table joins + internal static SQL.SQLSelectTableBase GetTableJoins(SQL.SQLSelectTable collectionTable, Type itemInstanceType, SQL.SQLSelectTableBase leftTable, SQL.SQLSelectTableJoins tableJoins) { - SQL.SQLSelectTableJoins tableJoins = new SQL.SQLSelectTableJoins(); - SQL.SQLSelectTableBase leftTable = collectionTable; - foreach (var fieldInfo in GetObjectReferenceEarlyBindingFieldsAndForBaseTypes(itemInstanceType)) { var fieldTypeAssembly = fieldInfo.ObjectReferenceFieldType.Assembly; // assume that the collection type is defined in the same assembly as the item instance type @@ -150,11 +164,14 @@ internal static SQL.SQLSelectTableJoins GetTableJoins(IDatabaseObjects collectio var tableJoin = tableJoins.Add(leftTable, SQL.SQLSelectTableJoin.Type.Inner, rightTable); tableJoin.Where.Add(new SQL.SQLFieldExpression(collectionTable, fieldInfo.FieldMappingName), SQL.ComparisonOperator.EqualTo, new SQL.SQLFieldExpression(new SQL.SQLSelectTable(fieldAssociatedCollectionInfo.TableName), fieldAssociatedCollectionInfo.DistinctFieldName)); leftTable = tableJoin; + + // Also traverse "horizontally" / to a greater depth along the reference chain to ensure that referenced objects which also reference other objects are added to the table joins + leftTable = GetTableJoins(new SQL.SQLSelectTable(fieldAssociatedCollectionInfo.TableName), fieldAssociatedCollectionInfo.ItemInstanceType, leftTable, tableJoins); } - - return tableJoins; + + return leftTable; } - + /// /// Traverses the item instance type and any base classes for reference to fields marked with the /// ObjectReferenceEarlyBindingAttribute.