Skip to content

Commit

Permalink
Added support for early binding object references. Closes #41.
Browse files Browse the repository at this point in the history
Utilises the DatabaseObjects.Generic.ObjectReference class in conjunction with the ObjectReferenceEarlyBindingAttribute to indicate that the foreign object should be loaded using a table join and loaded with the containing / referencing object. This avoids having to specify table joins as this is done automatically.
  • Loading branch information
hisystems committed Apr 8, 2012
1 parent 75ced7d commit ea8b776
Show file tree
Hide file tree
Showing 6 changed files with 352 additions and 19 deletions.
52 changes: 52 additions & 0 deletions Attributes/ObjectReferenceEarlyBindingAttribute.vb
@@ -0,0 +1,52 @@
' ___________________________________________________
'
' © Hi-Integrity Systems 2012. All rights reserved.
' www.hisystems.com.au - Toby Wicks
' ___________________________________________________
'

Option Strict On
Option Explicit On

''' <summary>
''' Attribute for a field of type DatabaseObjects.Generic.ObjectReference class.
''' Attribute cannot be applied to a DatabaseObjects.ObjectReference class - only the generic version.
'''
''' Indicates whether the foreign / referenced object should be loaded when the containing
''' object is loaded (early binding).
'''
''' If ommitted then the late binding is applied. Specifically, only the reference object's
''' distinct value will be assigned to the ObjectReference.DistinctValue property.
''' Subsequent calls to ObjectReference.Object will load the foreign / referenced.
'''
''' Early binding is achieved by joining the table with the foreign table and creating
''' the main object and the foreign / referenced object from the joined data.
''' The table joins are created automatically and are automatically implemented in the
''' DatabaseObjects.TableJoins function.
'''
''' ObjectReferenceEarlyBindingAttribute must be used with the FieldMappingAttribute to indicate
''' the name of the field in the primary collection's table that references the
''' foreign field / distinct value in the foreign collection.
''' The field specified MUST link to the foreign collection's distinct field and table name as indicated
''' by the TableAttribute and DistinctFieldAttribute values.
''' </summary>
''' <remarks>
''' The foreign collection table is determined by utilising the type T defined by
''' DatabaseObjects.Generic.ObjectReference and then obtaining the table name and distinct
''' field from the TableAttribute and DistinctFieldAttribute values.
''' </remarks>
<AttributeUsage(AttributeTargets.Field, AllowMultiple:=False, Inherited:=True)> _
Public Class ObjectReferenceEarlyBindingAttribute
Inherits Attribute

''' <summary>
''' Indicates that the referenced object should be loaded when the main object is loaded.
''' This is achieved using table joins.
''' Can only be used with a DatabaseObjects.Generic.ObjectReference class.
''' The foreign collection must specify the TableAttribute and DistinctFieldAttribute values.
''' </summary>
Public Sub New()

End Sub

End Class
11 changes: 11 additions & 0 deletions Database/DatabaseObjectUsingAttributesHelper.vb
Expand Up @@ -8,6 +8,7 @@

Option Strict On
Option Explicit On
Option Infer On

''' --------------------------------------------------------------------------------
''' <summary>
Expand Down Expand Up @@ -209,10 +210,20 @@ Public Module DatabaseObjectUsingAttributesHelper
LoadFieldsForBaseTypes(objObject, objType.BaseType, objFields)
LoadFieldsForObject(objObject, objType, objFields)
LoadFieldsForHookedObjects(objObject, objType, objFields)
LoadFieldsForObjectReferenceEarlyBinding(objObject, objType, objFields)
End If

End Sub

Private Sub LoadFieldsForObjectReferenceEarlyBinding(ByVal objectToLoad As Object, ByVal type As System.Type, ByVal fieldValues As SQL.SQLFieldValues)

For Each earlyBindingField In ObjectReferenceEarlyBinding.GetObjectReferenceEarlyBindingFields(type)
Dim objectReference = DirectCast(earlyBindingField.Field.GetValue(objectToLoad), ObjectReference)
objectReference.Object = Database.ObjectFromFieldValues(objectReference.ParentCollection, fieldValues)
Next

End Sub

Private Sub LoadFieldsForHookedObjects(ByVal objObject As Object, ByVal objType As System.Type, ByVal objFields As SQL.SQLFieldValues)

Dim objAttributes As Object()
Expand Down
65 changes: 46 additions & 19 deletions Database/DatabaseObjectsUsingAttributesHelper.vb
Expand Up @@ -74,20 +74,29 @@ Friend Class DatabaseObjectsUsingAttributesHelper

Public Function ItemInstance() As IDatabaseObject

Dim itemInstanceType As Type
Dim itemInstanceType = GetItemInstanceType()

Return DatabaseObjectsItemInstance.CreateItemInstance(itemInstanceType, pobjDatabaseObjects)

End Function

''' <summary>
''' Returns the item instance type to instantiate.
''' It may be defined as a T argument on a generic collection or explicitly
''' via the ItemInstance attribute.
''' </summary>
Private Function GetItemInstanceType() As Type

If pobjItemInstance Is Nothing Then
Try
itemInstanceType = DatabaseObjectsItemInstance.GetGenericCollectionTArgument(pobjDatabaseObjects.GetType)
Return DatabaseObjectsItemInstance.GetGenericCollectionTArgument(pobjDatabaseObjects.GetType)
Catch ex As Exceptions.DatabaseObjectsException
Throw New Exceptions.DatabaseObjectsException("ItemInstanceAttribute has not been specified and " + ex.Message)
End Try
Else
itemInstanceType = pobjItemInstance.Type
Return pobjItemInstance.Type
End If

Return DatabaseObjectsItemInstance.CreateItemInstance(itemInstanceType, pobjDatabaseObjects)

End Function

Public ReadOnly Property DistinctFieldName() As String
Expand Down Expand Up @@ -185,25 +194,43 @@ Friend Class DatabaseObjectsUsingAttributesHelper

Public Function TableJoins(ByVal objPrimaryTable As SQL.SQLSelectTable, ByVal objTables As SQL.SQLSelectTables) As SQL.SQLSelectTableJoins

Dim tableJoinsCollection As SQL.SQLSelectTableJoins

'If attribute was not specified
If pobjTableJoins.Count = 0 Then
Return Nothing
If pobjTableJoins.Count > 0 Then
tableJoinsCollection = TableJoinsFromAttributes(pobjTableJoins.ToArray, objPrimaryTable, objTables)
Else
Dim objTableJoins As SQL.SQLSelectTableJoins = New SQL.SQLSelectTableJoins
Dim leftTable As SQL.SQLSelectTableBase = objPrimaryTable
Dim leftTableName As String = objPrimaryTable.Name

For Each tableJoinAttribute In pobjTableJoins
Dim rightTable As SQL.SQLSelectTableBase = objTables.Add(tableJoinAttribute.ToTableName)
Dim tableJoin = objTableJoins.Add(leftTable, SQL.SQLSelectTableJoin.Type.Inner, rightTable)
tableJoin.Where.Add(New SQL.SQLFieldExpression(New SQL.SQLSelectTable(leftTableName), tableJoinAttribute.FieldName), SQL.ComparisonOperator.EqualTo, New SQL.SQLFieldExpression(New SQL.SQLSelectTable(tableJoinAttribute.ToTableName), tableJoinAttribute.ToFieldName))
leftTable = tableJoin
leftTableName = tableJoinAttribute.ToTableName
Next
'If the ObjectReferenceEarlyBindingAttribute is specified on the item instance then create the table joins that will be required
Dim earlyBindingTableJoins = ObjectReferenceEarlyBinding.GetTableJoins(pobjDatabaseObjects, objPrimaryTable, Me.GetItemInstanceType)

Return objTableJoins
If earlyBindingTableJoins.Count > 0 Then
tableJoinsCollection = earlyBindingTableJoins
Else
tableJoinsCollection = Nothing
End If
End If

Return tableJoinsCollection

End Function

Private Shared Function TableJoinsFromAttributes(tableJoinAttributes As TableJoinAttribute(), ByVal primaryTable As SQL.SQLSelectTable, ByVal tables As SQL.SQLSelectTables) As SQL.SQLSelectTableJoins

Dim tableJoinsCollection As New SQL.SQLSelectTableJoins

Dim leftTable As SQL.SQLSelectTableBase = primaryTable
Dim leftTableName As String = primaryTable.Name

For Each tableJoinAttribute In tableJoinAttributes
Dim rightTable As SQL.SQLSelectTableBase = tables.Add(tableJoinAttribute.ToTableName)
Dim tableJoin = tableJoinsCollection.Add(leftTable, SQL.SQLSelectTableJoin.Type.Inner, rightTable)
tableJoin.Where.Add(New SQL.SQLFieldExpression(New SQL.SQLSelectTable(leftTableName), tableJoinAttribute.FieldName), SQL.ComparisonOperator.EqualTo, New SQL.SQLFieldExpression(New SQL.SQLSelectTable(tableJoinAttribute.ToTableName), tableJoinAttribute.ToFieldName))
leftTable = tableJoin
leftTableName = tableJoinAttribute.ToTableName
Next

Return tableJoinsCollection

End Function


Expand Down
8 changes: 8 additions & 0 deletions Database/ObjectReference.vb
Expand Up @@ -179,6 +179,14 @@ Public Class ObjectReference
End Set
End Property

Friend ReadOnly Property ParentCollection As IDatabaseObjects
Get

Return pobjCollection

End Get
End Property

''' --------------------------------------------------------------------------------
''' <summary>
''' Returns whether the Object property would return Nothing.
Expand Down

0 comments on commit ea8b776

Please sign in to comment.