From: Richard B. <rb...@us...> - 2005-03-21 08:00:59
|
Update of /cvsroot/jcframework/dotnet In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9538 Modified Files: AtomsFramework.xml CClassMap.vb CInjectedObject.vb CMultiSummaryCriteria.vb CPersistenceBroker.vb CPersistentObject.vb IPersistentObject.vb Added Files: CQueuedDelete.vb Log Message: Bug fixes for Many-to-many associations, and missing OriginalCreatedDate for CInjectedObject. Added support for auto clean up of associations when removing items, without having to manually delete objects. Index: CMultiSummaryCriteria.vb =================================================================== RCS file: /cvsroot/jcframework/dotnet/CMultiSummaryCriteria.vb,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- CMultiSummaryCriteria.vb 16 Mar 2005 11:32:41 -0000 1.15 +++ CMultiSummaryCriteria.vb 21 Mar 2005 08:00:23 -0000 1.16 @@ -134,7 +134,6 @@ Public Sub New(ByVal obj As CPersistentObject) Me.New() - ' m_objectsToJoin.Add(obj) Me.addObjectToJoin(obj, Nothing, "") Me.ClassMap = obj.getClassMap(obj) End Sub @@ -268,7 +267,8 @@ strName = myArrayStrings(i) udaMap = clMap.AssociationMaps(strName) If udaMap Is Nothing Then - Throw New AToMSFramework.RetrieveException("Could not find association named " & strName & " for class " & clMap.Name) + Throw New AToMSFramework.RetrieveException("Could not find association named " & strName & " for class " & clMap.Name) + End If clMap = udaMap.ToClass If clMap Is Nothing Then Index: CPersistenceBroker.vb =================================================================== RCS file: /cvsroot/jcframework/dotnet/CPersistenceBroker.vb,v retrieving revision 1.100 retrieving revision 1.101 diff -u -d -r1.100 -r1.101 --- CPersistenceBroker.vb 16 Mar 2005 11:32:42 -0000 1.100 +++ CPersistenceBroker.vb 21 Mar 2005 08:00:23 -0000 1.101 @@ -637,7 +637,7 @@ Else targetobj = toClass.CreateObjectInstance rw = rs.ResultSet.Tables(0).Rows(i) - cm2.populateObject(cm2, targetobj, rw, mapName) + toClass.populateObject(toClass, targetobj, rw, mapName) If targetobj.Persistent Then If TypeOf (targetobj) Is CInjectedObject Then StartTracking(targetobj) @@ -2563,6 +2563,7 @@ Dim tmpObj As Object Dim aObj As CAssociationObject Dim isNewManyToMany As Boolean + Dim qd As CQueuedDelete If obj.IsQueued Then 'if an object has already been added to the save queue, there is no need to add @@ -2606,9 +2607,7 @@ If includeBaseObject AndAlso _ (obj.IsDirty AndAlso Not obj.IsProxy AndAlso Not obj.IsReadOnly AndAlso Not obj.IsModifyOnly) Then If GetType(IValidation).IsInstanceOfType(obj.GetSourceObject) Then - 'If obj.GetObjectType.IsSubclassOf(GetType(CPersistentObject)) Then If CType(obj.GetSourceObject, IValidation).IsValid Then 'Do not save if object is not valid - 'obj.IsDirty = False 'Added to queue so clear dirty flag AddToQueue(obj, queue) End If Else @@ -2646,6 +2645,30 @@ Next Next k End If + 'Now go through and find out which objects have been removed from the collection + 'and attempt to modify and/or delete them. + For Each value In obj.GetRemovedCollectionItems(udamap.FromClassTarget) + If udamap.DeleteAutomatic = True Then + 'Delete the object + qd = New CQueuedDelete + qd.ObjectToDelete = value + queue.Enqueue(qd) + Else + For Each e As CUDAMapEntry In udamap.Entries + 'Try to set to nothing first. If it fails set the value to NULL alias value + 'Need to do a get first so we know what type to alias + Try + value.SetAttributeValue(e.ToAttrMap.Name, Nothing) + Catch ex As Exception + tmpObj = value.GetValueByAttribute(e.ToAttrMap.Name) + modAliasNull.NullToAlias(DBNull.Value, tmpObj) + value.SetAttributeValue(e.ToAttrMap.Name, tmpObj) + End Try + Next + 'Now add object to list to be saved + queue.Enqueue(value) + End If + Next ElseIf udamap.Cardinality = CUDAMap.CardinalityEnum.MANY_TO_MANY Then If obj.GetClassMap.Name = udamap.FromClass.Name Then col = obj.GetCollectionByAttribute(udamap.FromClassTarget) @@ -2706,7 +2729,7 @@ ''' </history> ''' ----------------------------------------------------------------------------- Function getObjectsToSave(ByVal obj As CPersistentObject) As Queue - Return getObjectsToSave(obj, True, False) + Return getObjectsToSave(obj, True, True) End Function ''' ----------------------------------------------------------------------------- @@ -2850,7 +2873,8 @@ End Sub Public Function getInjectedObject(ByVal obj As Object) As CInjectedObject - Return getInjectedObject(obj, False) + Return getInjectedObject(obj, False) + End Function Public Function getInjectedObject(ByVal obj As Object, ByVal createTemporary As Boolean) As CInjectedObject @@ -2863,7 +2887,7 @@ 'recursively referencing each other we need to add the objects to the cache 'in order to prevent nested recursion. This temporary addition is only 'used in getObjectsToSave - m_injectedObjects.AddTemp(injObj, True) + m_injectedObjects.AddTemp(injObj, True) End If End If Return injObj @@ -2930,13 +2954,13 @@ For Each de As DictionaryEntry In objectsToPersist injObj = de.Value If Not injObj.MarkedForDeletion Then - PersistChanges(injObj.ReferencedObject) + PersistChanges(injObj.ReferencedObject, checkAssociationsRecursively) End If Next For Each de As DictionaryEntry In objectsToPersist injObj = de.Value If injObj.MarkedForDeletion And injObj.Persistent Then - PersistChanges(injObj.ReferencedObject) + PersistChanges(injObj.ReferencedObject, checkAssociationsRecursively) End If Next m_inPersistChangesLoop = False @@ -2959,9 +2983,9 @@ Public Sub PersistChanges(ByVal obj As Object, ByVal checkAssociationsRecursively As Boolean) Dim value As IPersistableObject - Dim queue As Queue + Dim queue As queue Dim qObject As Object - Dim injObj As CInjectedObject + Dim injObj, tmpObj As CInjectedObject Dim ckey As CCacheKey Dim savedKeys As New ArrayList @@ -2987,6 +3011,17 @@ Try If GetType(CAssociationObject).IsInstanceOfType(qObject) Then saveAssociationObject(qObject) + ElseIf GetType(CQueuedDelete).IsInstanceOfType(qObject) Then + Try + tmpObj = CType(qObject, CQueuedDelete).ObjectToDelete + deleteObject(tmpObj, tmpObj.WillDeleteParents) + If Not m_inPersistChangesLoop Then + m_injectedObjects.Remove(tmpObj) + End If + Catch ex As Exception + Debug.WriteLine("(QueuedDelete) Tried to delete an object that was already deleted") + Debug.WriteLine(ex.Message) + End Try Else value = qObject ckey = New CCacheKey(value) @@ -2995,6 +3030,8 @@ Debug.WriteLine("The object with key " & ckey.ToString & " was already saved once") Else saveObject(value) + 'Recopy one-to-many collections incase object is resaved later + value.CopyOneToManyCollections() 'Recalculate key value - required when identity columns are used ckey = New CCacheKey(value) savedKeys.Add(ckey) @@ -3014,7 +3051,7 @@ End If End If If Not m_inPersistChangesLoop Then - m_injectedObjects.CleanUp() + m_injectedObjects.CleanUp() End If End Sub @@ -3220,6 +3257,69 @@ Next End Sub + ''' ----------------------------------------------------------------------------- + ''' <summary> + ''' Makes a copy of a collection as referenced by the propertyname parameter + ''' </summary> + ''' <param name="fromObject">The object to copy from</param> + ''' <param name="propertyName">The property of the from object to copy</param> + ''' <returns>A collection.</returns> + ''' <remarks>Event handlers not copied. + ''' </remarks> + ''' <history> + ''' [rbanks] 21/03/2005 Created + ''' </history> + ''' ----------------------------------------------------------------------------- + Friend Shared Function CopyCollection(ByVal fromObject As IPersistableObject, ByVal propertyName As String) As Object + Dim t, iListType, iDicType As Type + Dim fromColl, toColl, collItem As Object + Dim il As IList + Dim id As IDictionary + Dim p As PropertyInfo + Dim tmpObj As Object + + fromColl = fromObject.GetCollectionByAttribute(propertyName) + If fromColl Is Nothing Then + Return Nothing + End If + + p = fromObject.GetObjectType.GetProperty(propertyName, BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public) + iListType = p.PropertyType.GetInterface("IList", True) + iDicType = p.PropertyType.GetInterface("IDictionary", True) + If Not iListType Is Nothing OrElse Not iDicType Is Nothing Then + Dim ICloneType As Type = p.PropertyType.GetInterface("ICloneable", True) + If Not ICloneType Is Nothing Then + 'Getting the ICloneable interface from the object. + tmpObj = p.GetValue(fromObject.GetSourceObject, Nothing) + If Not tmpObj Is Nothing Then + Dim IClone As ICloneable = CType(tmpObj, ICloneable) + toColl = IClone.Clone() + Else + toColl = Nothing + End If + Return toColl + Else + 'If the field doesn't support the ICloneable interface then just set it. + 'need to copy collection members one by one + t = p.PropertyType + toColl = Activator.CreateInstance(t) + Dim fColl, fieldsColl() As FieldInfo + If Not iListType Is Nothing Then + il = CType(toColl, IList) + For Each collItem In fromColl + il.Add(collItem) + Next + Else + id = CType(toColl, IDictionary) + For Each de As DictionaryEntry In fromColl + id.Add(de.Key, de.Value) + Next + End If + End If + End If + Return toColl + End Function + Private Sub AddToQueue(ByVal obj As Object, ByRef queue As Queue) Call AddToQueue(obj, queue, True) End Sub Index: IPersistentObject.vb =================================================================== RCS file: /cvsroot/jcframework/dotnet/IPersistentObject.vb,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- IPersistentObject.vb 3 Mar 2005 00:38:24 -0000 1.10 +++ IPersistentObject.vb 21 Mar 2005 08:00:25 -0000 1.11 @@ -7,6 +7,7 @@ Property GUIDValue() As String Property CreatedDate() As Date Property ModifiedDate() As Date + ReadOnly Property OriginalCreatedDate() As Date Property OriginalModifiedDate() As Date Property AssociationsLoaded() As Boolean Property IsLoading() As Boolean @@ -25,6 +26,9 @@ Function GetValueByAttribute(ByVal pName As String) As Object Sub SetAttributeValue(ByVal pName As String, ByRef Value As Object) + Function GetRemovedCollectionItems(ByVal propertyName As String) As Collection + Sub CopyOneToManyCollections() + Function GetObjectType() As Type Function Equals(ByVal obj As IPersistableObject) As Boolean Function Copy() As IPersistableObject Index: CClassMap.vb =================================================================== RCS file: /cvsroot/jcframework/dotnet/CClassMap.vb,v retrieving revision 1.53 retrieving revision 1.54 diff -u -d -r1.53 -r1.54 --- CClassMap.vb 11 Mar 2005 04:40:55 -0000 1.53 +++ CClassMap.vb 21 Mar 2005 08:00:22 -0000 1.54 @@ -1869,7 +1869,7 @@ classMapCount += 1 mapName = "t" & classMapCount.ToString If udamap.Cardinality = CUDAMap.CardinalityEnum.MANY_TO_MANY AndAlso Me.Name <> udamap.FromClass.Name Then - rMaps.Add(mapName, udamap.ToClass) + rMaps.Add(mapName, udamap.FromClass) m_joinSet = New CJoin(m_joinSet, udamap.FromClass, mapName, udamap) pbroker.createJoinForMultipleInheritance(udamap.FromClass, classMapCount, m_joinSet, rMaps) Else @@ -1996,11 +1996,17 @@ If udamap.RetrieveAutomatic Then classMapCount += 1 mapName = "t" & classMapCount.ToString + If udamap.Cardinality = CUDAMap.CardinalityEnum.MANY_TO_MANY AndAlso Me.Name <> udamap.FromClass.Name Then + rMaps.Add(mapName, udamap.FromClass) + m_joinSet = New CJoin(m_joinSet, udamap.FromClass, mapName, udamap) + pbroker.createJoinForMultipleInheritance(udamap.FromClass, classMapCount, m_joinSet, rMaps) + Else rMaps.Add(mapName, udamap.ToClass) m_joinSet = New CJoin(m_joinSet, udamap.ToClass, mapName, udamap) 'Add joins for multiple inheritance pbroker.createJoinForMultipleInheritance(udamap.ToClass, classMapCount, m_joinSet, rMaps) End If + End If Next 'Now build the SQL statement --- NEW FILE: CQueuedDelete.vb --- ''' ----------------------------------------------------------------------------- ''' <summary> ''' Class used for adding an object to delete to the queue of objects to save ''' </summary> ''' <remarks> ''' Specifically used for automatic clean up of one-to-many associations and ''' created during the GetObjectsToSave method. ''' </remarks> ''' <history> ''' [rbanks] 21/03/2005 Created ''' </history> ''' ----------------------------------------------------------------------------- Friend Class CQueuedDelete Private m_object As IPersistableObject Public Property ObjectToDelete() As IPersistableObject Get Return m_object End Get Set(ByVal Value As IPersistableObject) m_object = Value End Set End Property End Class Index: AtomsFramework.xml =================================================================== RCS file: /cvsroot/jcframework/dotnet/AtomsFramework.xml,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- AtomsFramework.xml 6 Feb 2005 02:44:00 -0000 1.9 +++ AtomsFramework.xml 21 Mar 2005 08:00:15 -0000 1.10 @@ -1,7258 +1,6601 @@ -<?xml version="1.0"?> -<doc> - <assembly> - <name>AToMSFramework</name> - <version>2.1.0.0</version> - <fullname>AToMSFramework, Version=2.1.0.0, Culture=neutral, PublicKeyToken=e5c3a6c915b93944</fullname> - </assembly> - <members> - <member name="T:AToMSFramework.AFTableAttribute"> - <summary> - Custom attribute to define table mappings for a class [...13828 lines suppressed...] + <history> + [rbanks] 18/12/2003 Created + </history></member><member name="T:AToMSFramework.modOIDFactorySingleton"><summary> + Module for managing the ObjectID Factory singleton object + </summary> + <remarks>Manages the references to the singleton <see cref="T:AToMSFramework.COIDFactory" /> object.</remarks> + <history> + [rbanks] 18/12/2003 Created + </history></member><member name="M:AToMSFramework.modOIDFactorySingleton.getOIDFactoryInstance"><summary> + Gets a reference to the COIDFactory instance. + </summary> + <returns>A reference to the COIDFactory object.</returns> + <remarks>If the <see cref="M:AToMSFramework.modOIDFactorySingleton.getOIDFactoryInstance" /> instance does not yet + exist it is created.</remarks> + <history> + [rbanks] 18/12/2003 Created + </history></member></para></remarks></member> + </members> </doc> \ No newline at end of file Index: CInjectedObject.vb =================================================================== RCS file: /cvsroot/jcframework/dotnet/CInjectedObject.vb,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- CInjectedObject.vb 17 Mar 2005 06:14:36 -0000 1.18 +++ CInjectedObject.vb 21 Mar 2005 08:00:23 -0000 1.19 @@ -26,6 +26,7 @@ Private m_proxy As Boolean Private m_markedForDeletion As Boolean Private m_deleteParents As Boolean + Private m_oneToManyCollections As New Collection Public Sub New(ByVal obj As Object) MyBase.New() @@ -76,7 +77,8 @@ End If Dim f, fields() As FieldInfo Dim value As Object - Dim t, iListType, iDicType As Type Try + Dim t, iListType, iDicType As Type + Try t = sourceObject.GetType While Not t Is Nothing fields = t.GetFields(BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public) @@ -96,7 +98,8 @@ t = Nothing End If End While - CPersistenceBroker.CopyCollections(sourceObject, targetObject) Catch ex As Exception + CPersistenceBroker.CopyCollections(sourceObject, targetObject) + Catch ex As Exception Debug.WriteLine(ex.Message) End Try End Sub @@ -104,65 +107,13 @@ Public Function getClassMap() As CClassMap Implements IPersistableObject.getClassMap Dim tmpCMap As CClassMap If m_classmap Is Nothing Then - 'm_classmap = getClassMap(TypeName(m_object), m_object.GetType.FullName) - 'If m_classmap Is Nothing Then - Dim persistenceBroker As CPersistenceBroker - persistenceBroker = getPersistenceBrokerInstance() - m_classmap = persistenceBroker.getClassMap(m_object.GetType) - - ''try to find an interface that is mapped - first mapped interface we find will be used - 'Dim intType, tmpType, interfaces() As Type - 'interfaces = m_object.GetType.GetInterfaces - - ''----------------------------------------- - 'Dim n, m As Integer - 'Dim super As CClassMap - - '' get the super class map if the object has multi-level inheritance - 'For n = 0 To interfaces.Length - 1 - ' m_classmap = getClassMap(interfaces(n).Name, interfaces(n).FullName) - ' If (Not m_classmap Is Nothing) AndAlso m_classmap.SuperClass Is Nothing Then - ' super = m_classmap - ' For m = n To interfaces.Length - 2 - ' interfaces(m) = interfaces(m + 1) - ' Next - ' If interfaces.Length > 1 Then - ' interfaces(m) = Nothing - ' End If - ' Exit For - ' End If - 'Next - - ''get actual interface which is the bottom level of inheritance - 'n = 0 - 'While n < interfaces.Length - 1 - ' If Not interfaces(n) Is Nothing Then - ' tmpCMap = getClassMap(interfaces(n).Name, interfaces(n).FullName) - ' If (Not tmpCMap Is Nothing) AndAlso tmpCMap.SuperClass Is super Then - ' super = tmpCMap - ' m_classmap = super - ' For m = n To interfaces.Length - 2 - ' interfaces(m) = interfaces(m + 1) - ' Next - ' interfaces(m) = Nothing - - ' If interfaces(0) Is Nothing Then - ' m_classmap = tmpCMap - ' Exit While - ' End If - ' n = 0 - ' Else - ' n = n + 1 - ' End If - ' Else - ' n = n + 1 - ' End If - 'End While - End If - If (m_classmap Is Nothing) Then - Throw New NoClassMapException("No class map for " & m_object.GetType.FullName) - End If - 'End If + Dim persistenceBroker As CPersistenceBroker + persistenceBroker = getPersistenceBrokerInstance() + m_classmap = persistenceBroker.getClassMap(m_object.GetType) + End If + If (m_classmap Is Nothing) Then + Throw New NoClassMapException("No class map for " & m_object.GetType.FullName) + End If Return m_classmap End Function @@ -188,18 +139,18 @@ Return m_object.GetType End Function - Public Function getValueByAttribute(ByVal pName As String) As Object Implements IPersistableObject.getValueByAttribute + Public Function getValueByAttribute(ByVal obj As Object, ByVal pName As String) As Object Dim dotPos As Integer dotPos = pName.IndexOf(".") If dotPos = -1 Then - Return CallByName(m_object, pName, CallType.Get) + Return CallByName(obj, pName, CallType.Get) Else Dim o As Object Dim objName As String Dim propertyName As String objName = pName.Substring(0, dotPos) propertyName = pName.Substring(dotPos + 1) - o = CallByName(m_object, objName, CallType.Get) + o = CallByName(obj, objName, CallType.Get) If o Is Nothing Then Return Nothing End If @@ -207,23 +158,12 @@ End If End Function + Public Function getValueByAttribute(ByVal pName As String) As Object Implements IPersistableObject.getValueByAttribute + Return getValueByAttribute(m_object, pName) + End Function + Public Function getOriginalValueByAttribute(ByVal pName As String) As Object - Dim dotPos As Integer - dotPos = pName.IndexOf(".") - If dotPos = -1 Then - Return CallByName(m_originalObject, pName, CallType.Get) - Else - Dim o As Object - Dim objName As String - Dim propertyName As String - objName = pName.Substring(0, dotPos) - propertyName = pName.Substring(dotPos + 1) - o = CallByName(m_originalObject, objName, CallType.Get) - If o Is Nothing Then - Return Nothing - End If - Return CallByName(o, propertyName, CallType.Get) - End If + Return getValueByAttribute(m_originalObject, pName) End Function Public Property AssociationsLoaded() As Boolean Implements IPersistableObject.AssociationsLoaded @@ -292,7 +232,6 @@ End Property Public Function ObjectsMatch(ByVal sourceObject As Object, ByVal targetObject As Object) As Boolean - 'Use reflection to compare all of the fields from sourceObj to targetobject (by value) If sourceObject Is Nothing AndAlso targetObject Is Nothing Then Return True If sourceObject Is Nothing OrElse targetObject Is Nothing Then Return False If Not sourceObject.GetType Is targetObject.GetType Then @@ -310,10 +249,10 @@ While Not cmap Is Nothing For Each att As CAttributeMap In cmap.AttributeMaps If Not att.ColumnMap Is Nothing Then - value = getValueByAttribute(att.Name) - value1 = getOriginalValueByAttribute(att.Name) + value = getValueByAttribute(sourceObject, att.Name) + value1 = getValueByAttribute(targetObject, att.Name) If Not Equals(value, value1) Then - Return True + Return False End If End If Next @@ -323,38 +262,13 @@ cmap = Nothing End If End While - Return False + Return True - 'Dim f, fields() As FieldInfo - 'Dim t As Type - 'Try - ' t = sourceObject.GetType - ' While Not t Is Nothing - ' fields = t.GetFields(BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public) - ' 'Note that this will copy event handlers as well - ' For Each f In fields - ' value = f.GetValue(sourceObject) - ' value1 = f.GetValue(targetObject) - ' If Not Equals(value, value1) Then - ' Return True - ' End If - ' Next - ' If Not t.BaseType Is Nothing Then - ' t = t.BaseType - ' Else - ' t = Nothing - ' End If - ' End While - 'Catch ex As Exception - ' Debug.WriteLine(ex.Message) - ' Return False - 'End Try - 'Return False End Function Public Property IsDirty() As Boolean Implements IPersistableObject.IsDirty Get - Return ObjectsMatch(m_object, m_originalObject) + Return Not ObjectsMatch(m_object, m_originalObject) End Get Set(ByVal Value As Boolean) 'For injected objects this should only be called from the persistence broker and @@ -372,6 +286,9 @@ Return m_loading End Get Set(ByVal Value As Boolean) + If m_loading <> Value AndAlso Value = False Then + CopyOneToManyCollections() + End If m_loading = Value End Set End Property @@ -502,8 +419,8 @@ pbroker = getPersistenceBrokerInstance() injobj = pbroker.getInjectedObject(obj) End If - Catch err As Exception - Throw New Exception("getObjectByAttribute failed for attribute " & pName & " in " & m_object.GetType.FullName, err) + Catch ex As Exception + Throw New Exception("getObjectByAttribute failed for attribute " & pName & " in " & m_object.GetType.FullName, ex) End Try Return injobj End Function @@ -661,6 +578,12 @@ End Set End Property + Public ReadOnly Property OriginalCreatedDate() As Date Implements IPersistableObject.OriginalCreatedDate + Get + Return m_createdDate + End Get + End Property + Public Overrides Function ToString() As String Dim s As String Dim i As Short @@ -728,5 +651,97 @@ Next Return False End Function + + Private Sub CopyOneToManyCollections() Implements IPersistableObject.CopyOneToManyCollections + Dim cm As CClassMap + Dim coll As Object + cm = Me.getClassMap + m_oneToManyCollections = New Collection + Dim aMap As CUDAMap + For Each de As DictionaryEntry In cm.AssociationMaps + aMap = de.Value + If aMap.Cardinality = aMap.CardinalityEnum.ONE_TO_MANY Then + coll = CPersistenceBroker.CopyCollection(Me, aMap.FromClassTarget) + m_oneToManyCollections.Add(coll, aMap.FromClassTarget) + End If + Next + End Sub + + Public Function GetRemovedCollectionItems(ByVal propertyName As String) As Collection Implements IPersistableObject.GetRemovedCollectionItems + Dim t, iListType, iDicType As Type + Dim fromColl, origColl, collItem As Object + Dim fromIList, origIList As IList + Dim fromDict, origDict As IDictionary + Dim p As PropertyInfo + Dim tmpObj As Object + Dim toColl As New Collection + Dim injObj As IPersistableObject + + Try + origColl = m_oneToManyCollections.Item(propertyName) + Catch + origColl = Nothing + End Try + If origColl Is Nothing Then Return toColl + + p = Me.GetObjectType.GetProperty(propertyName, BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public) + iListType = p.PropertyType.GetInterface("IList", True) + iDicType = p.PropertyType.GetInterface("IDictionary", True) + If Not iListType Is Nothing OrElse Not iDicType Is Nothing Then + If Not iListType Is Nothing Then + origIList = CType(origColl, IList) + fromIList = CType(Me.getValueByAttribute(propertyName), IList) + For Each collItem In origIList + If NotInCollection(fromIList, collItem) Then + If Not TypeOf collItem Is IPersistableObject Then + injObj = getPersistenceBrokerInstance.getInjectedObject(collItem, True) + Else + injObj = collItem + End If + toColl.Add(injObj) + End If + Next + Else + origDict = CType(origColl, IDictionary) + fromDict = CType(Me.getValueByAttribute(propertyName), IDictionary) + For Each de As DictionaryEntry In origColl + If NotInCollection(fromDict, de.Key) Then + If Not TypeOf collItem Is IPersistableObject Then + injObj = getPersistenceBrokerInstance.getInjectedObject(de.Value, True) + Else + injObj = de.Value + End If + toColl.Add(injObj) + End If + Next + End If + End If + Return toColl + End Function + + Private Function NotInCollection(ByVal coll As IList, ByVal item As Object) As Boolean + Try + If coll.Contains(item) Then + Return False + Else + Return True + End If + Catch ex As Exception + Return True + End Try + End Function + + Private Function NotInCollection(ByVal coll As IDictionary, ByVal key As Object) As Boolean + Try + If coll.Contains(key) Then + Return False + Else + Return True + End If + Catch ex As Exception + Return True + End Try + End Function + End Class Index: CPersistentObject.vb =================================================================== RCS file: /cvsroot/jcframework/dotnet/CPersistentObject.vb,v retrieving revision 1.58 retrieving revision 1.59 diff -u -d -r1.58 -r1.59 --- CPersistentObject.vb 3 Mar 2005 00:38:24 -0000 1.58 +++ CPersistentObject.vb 21 Mar 2005 08:00:25 -0000 1.59 @@ -54,9 +54,10 @@ Friend Event RemoveMe(ByVal pObj As CPersistentObject) <NonSerialized()> Private m_preEditCopy As CPersistentObject - <NonSerialized()> Private m_retrievedCacheKey As CCacheKey + <NonSerialized()> Private m_oneToManyCollections As New Collection + #Region "Properties" '''----------------------------------------------------------------------------- ''' <summary> @@ -412,7 +413,7 @@ ''' [rbanks] 25/11/2003 Created ''' </history> '''----------------------------------------------------------------------------- - <Browsable(False)> Public ReadOnly Property OriginalCreatedDate() As Date + <Browsable(False)> Public ReadOnly Property OriginalCreatedDate() As Date Implements IPersistableObject.OriginalCreatedDate Get Return m_createdDate End Get @@ -441,6 +442,9 @@ RaiseEvent LoadStarted(Me, New EventArgs) Else RaiseEvent LoadFinished(Me, New EventArgs) + 'Also need to copy collections for one-to-many associations so that we + 'have a reference point when figuring out what changed. + CopyOneToManyCollections() End If End If m_isLoading = Value @@ -914,6 +918,13 @@ Try If GetType(CAssociationObject).IsInstanceOfType(qObject) Then persistentBroker.saveAssociationObject(qObject) + ElseIf GetType(CQueuedDelete).IsInstanceOfType(qObject) Then + Try + persistentBroker.deleteObject(CType(qObject, CQueuedDelete).ObjectToDelete) + Catch ex As Exception + Debug.WriteLine("(Queued Delete) Tried to delete an object that has already been removed") + Debug.WriteLine(ex.Message) + End Try Else value = qObject 'Normal object saving @@ -923,6 +934,8 @@ Debug.WriteLine("The object with key " & ckey.ToString & " was already saved once") Else persistentBroker.saveObject(value) + 'Recopy one-to-many collections incase object is resaved later + value.CopyOneToManyCollections() 'Need to recalculate the key here to handle objects using identity (autonumber) keys ckey = New CCacheKey(value) savedKeys.Add(ckey) @@ -1294,7 +1307,8 @@ End If Dim f, fields() As FieldInfo Dim value As Object - Dim t, iListType, iDicType As Type Try + Dim t, iListType, iDicType As Type + Try t = Me.GetType While Not t Is Nothing fields = t.GetFields(BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public) @@ -1314,7 +1328,8 @@ t = Nothing End If End While - CPersistenceBroker.CopyCollections(obj, Me) Catch ex As Exception + CPersistenceBroker.CopyCollections(obj, Me) + Catch ex As Exception Debug.WriteLine(ex.Message) End Try End Sub @@ -1705,6 +1720,97 @@ Return obj End Function + Private Sub CopyOneToManyCollections() Implements IPersistableObject.CopyOneToManyCollections + Dim cm As CClassMap + Dim coll As Object + cm = Me.getClassMap + m_oneToManyCollections = New Collection + Dim aMap As CUDAMap + For Each de As DictionaryEntry In cm.AssociationMaps + aMap = de.Value + If aMap.Cardinality = aMap.CardinalityEnum.ONE_TO_MANY Then + coll = CPersistenceBroker.CopyCollection(Me, aMap.FromClassTarget) + m_oneToManyCollections.Add(coll, aMap.FromClassTarget) + End If + Next + End Sub + + Public Function GetRemovedCollectionItems(ByVal propertyName As String) As Collection Implements IPersistableObject.GetRemovedCollectionItems + Dim t, iListType, iDicType As Type + Dim fromColl, origColl, collItem As Object + Dim fromIList, origIList As IList + Dim fromDict, origDict As IDictionary + Dim p As PropertyInfo + Dim tmpObj As Object + Dim toColl As New Collection + Dim injobj As IPersistableObject + + Try + origColl = m_oneToManyCollections.Item(propertyName) + Catch + origColl = Nothing + End Try + If origColl Is Nothing Then Return toColl + + p = Me.GetObjectType.GetProperty(propertyName, BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public) + iListType = p.PropertyType.GetInterface("IList", True) + iDicType = p.PropertyType.GetInterface("IDictionary", True) + If Not iListType Is Nothing OrElse Not iDicType Is Nothing Then + If Not iListType Is Nothing Then + origIList = CType(origColl, IList) + fromIList = CType(Me.getValueByAttribute(propertyName), IList) + For Each collItem In origIList + If NotInCollection(fromIList, collItem) Then + If Not TypeOf collItem Is IPersistableObject Then + injObj = getPersistenceBrokerInstance.getInjectedObject(collItem, True) + Else + injObj = collItem + End If + toColl.Add(collItem) + End If + Next + Else + origDict = CType(origColl, IDictionary) + fromDict = CType(Me.getValueByAttribute(propertyName), IDictionary) + For Each de As DictionaryEntry In origColl + If NotInCollection(fromDict, de.Key) Then + If Not TypeOf collItem Is IPersistableObject Then + injobj = getPersistenceBrokerInstance.getInjectedObject(de.Value, True) + Else + injobj = de.Value + End If + toColl.Add(de.Value) + End If + Next + End If + End If + Return toColl + End Function + + Private Function NotInCollection(ByVal coll As IList, ByVal item As Object) As Boolean + Try + If coll.Contains(item) Then + Return False + Else + Return True + End If + Catch ex As Exception + Return True + End Try + End Function + + Private Function NotInCollection(ByVal coll As IDictionary, ByVal key As Object) As Boolean + Try + If coll.Contains(key) Then + Return False + Else + Return True + End If + Catch ex As Exception + Return True + End Try + End Function + #End Region #Region "IEditableObject" |