From: Richard B. <rb...@us...> - 2005-02-28 23:08:07
|
Update of /cvsroot/jcframework/dotnet In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16713 Modified Files: CCacheEntry.vb CClassMap.vb CCursor.vb CInjectedObject.vb CInjectedObjects.vb CMultiRetrieveCriteria.vb CPersistenceBroker.vb CPersistentObject.vb Log Message: Added ability to use many-to-many associations on non-inherited classes/interfaces Fixed numerous bugs in the injection cache Added restriction that injected obejcts must have key values populated before they can be tracked. Fixes a few other minor issues. Index: CPersistenceBroker.vb =================================================================== RCS file: /cvsroot/jcframework/dotnet/CPersistenceBroker.vb,v retrieving revision 1.95 retrieving revision 1.96 diff -u -d -r1.95 -r1.96 --- CPersistenceBroker.vb 14 Feb 2005 02:23:10 -0000 1.95 +++ CPersistenceBroker.vb 28 Feb 2005 23:07:53 -0000 1.96 @@ -8,7 +8,7 @@ Imports System.Text '''----------------------------------------------------------------------------- -''' Project : AToMSFramework +''' Project : Atoms.Framework ''' Class : CPersistenceBroker ''' '''----------------------------------------------------------------------------- @@ -35,7 +35,8 @@ Private m_cache As CCacheCollection 'object collection cache - stores persistent objects Private m_useCache As Boolean Private m_loaded As Boolean - Private m_injectedObjects As New CInjectedObjects + Private m_injectedObjects As New CInjectedObjectCache + Private m_objectsToDelete As New ArrayList Public Event LoginDetailsNeeded(ByVal sender As Object, ByRef User As String, ByRef Password As String) @@ -181,7 +182,7 @@ conn = cm.RelationalDatabase.getConnection(Nothing) conn.AutoCommit = False Try - retrieveObject = retrievePrivateObject(obj, conn, useFind, useCache) + obj.Persistent = retrievePrivateObject(obj, conn, useFind, useCache) Catch ex As Exception x = New RetrieveException(ex.Message, ex) Finally @@ -196,6 +197,7 @@ Throw x End If End Try + Return obj.Persistent End SyncLock End Function @@ -497,10 +499,12 @@ 'Object doesn't exist - let's create it 'See if the assembly path is specified targetobj = udamap.ToClass.CreateObjectInstance - If Not targetobj Is Nothing Then cm2.populateObject(cm2, targetobj, rs, mapName) If targetobj.Persistent Then + If TypeOf (targetobj) Is CInjectedObject Then + StartTracking(targetobj) + End If tmpObj = m_cache.Item(targetobj) If Not (tmpObj Is Nothing) Then targetobj = tmpObj @@ -549,6 +553,16 @@ fromClass = udamap.ToClass End If End If + 'When retrieving we need to make sure the collection is cleared before + 'we go an load objects. + ' Under normal circumstances this will be the case, however when the + 'collection is in a many-to-many associations it is possible for + 'one side to be cleared, but for the other object to still + 'have the reference in place. (see the unit tests for an example) + If i = 0 Then + 'Obviously we don't want to clear it each time through ;-) + col.Clear() + End If 'Check whether the object is of child type If toClass.ChildrenMaps.Count > 0 Then @@ -580,7 +594,7 @@ If tmpColObj.GetType.IsSubclassOf(GetType(CPersistentObject)) Then tmpObj = tmpColObj Else - tmpObj = LocateOrCreateInjObject(tmpColObj) + tmpObj = getInjectedObject(tmpColObj) End If If tmpObj.Equals(targetobj) Then gotValue = True @@ -610,6 +624,9 @@ rw = rs.ResultSet.Tables(0).Rows(i) cm2.populateObject(cm2, targetobj, rw, mapName) If targetobj.Persistent Then + If TypeOf (targetobj) Is CInjectedObject Then + StartTracking(targetobj) + End If tmpObj = m_cache.Item(targetobj) If Not (tmpObj Is Nothing) Then targetobj = tmpObj @@ -632,7 +649,7 @@ If tmpColObj.GetType.IsSubclassOf(GetType(CPersistentObject)) Then tmpObj = tmpColObj Else - tmpObj = LocateOrCreateInjObject(tmpColObj) + tmpObj = getInjectedObject(tmpColObj) End If If tmpObj.Equals(targetobj) Then gotValue = True @@ -657,7 +674,7 @@ End If End If End If - End If + End If End If Next Next @@ -1139,6 +1156,9 @@ PCSQLHits.Increment() Catch End Try + If TypeOf (obj) Is CInjectedObject Then + m_objectsToDelete.Add(obj) + End If conn.processStatement(statement) If deleteSuperClass Then cm = cm.SuperClass @@ -2070,7 +2090,7 @@ ''' information. ''' </summary> ''' <param name="pAsm">The assembly being processed</param> - ''' <remarks>The assembly is scanned for an of the AtomsFramework custom attributes and + ''' <remarks>The assembly is scanned for an of the Atoms.Framework custom attributes and ''' should any be found they are processed and the O/R mappings generated. ''' <para>This method is called once the XML file has been processed</para> ''' </remarks> @@ -2827,36 +2847,33 @@ Public Sub GetObject(ByRef obj As Object) Dim injObj As CInjectedObject - If injObj Is Nothing Then - injObj = New CInjectedObject(obj) - retrieveObject(injObj, False, True) - m_injectedObjects.Add(injObj) - obj = injObj.GetSourceObject - Else - obj = injObj.GetSourceObject - End If + injObj = LocateOrCacheInjObject(obj) + retrieveObject(injObj, False, True) + obj = injObj.GetSourceObject End Sub Public Sub FindObject(ByRef obj As Object) + Dim needToAdd As Boolean = False Dim injObj As CInjectedObject - injObj = m_injectedObjects.LocateObject(obj) + injObj = m_injectedObjects.Find(obj, True) If injObj Is Nothing Then injObj = New CInjectedObject(obj) - retrieveObject(injObj, True, True) - m_injectedObjects.Add(injObj) - obj = injObj.GetSourceObject - Else - obj = injObj.GetSourceObject + 'Being a find we will not have key values until after the retrieve completes + needToAdd = True + End If + retrieveObject(injObj, True, True) + If needToAdd Then + Try + m_injectedObjects.Add(injObj) + Catch ex As Exception + End Try End If + obj = injObj.GetSourceObject End Sub Public Function getInjectedObject(ByVal obj As Object) As CInjectedObject - Return m_injectedObjects.LocateObject(obj) - End Function - - Public Function LocateOrCreateInjObject(ByVal obj As Object) As CInjectedObject Dim injObj As CInjectedObject - injObj = m_injectedObjects.LocateObject(obj) + injObj = m_injectedObjects.Find(obj) If injObj Is Nothing Then injObj = New CInjectedObject(obj) End If @@ -2865,7 +2882,7 @@ Public Function LocateOrCacheInjObject(ByVal obj As Object) As CInjectedObject Dim injObj As CInjectedObject - injObj = m_injectedObjects.LocateObject(obj) + injObj = m_injectedObjects.Find(obj) If injObj Is Nothing Then injObj = New CInjectedObject(obj) m_injectedObjects.Add(injObj) @@ -2874,9 +2891,13 @@ End Function Public Sub StartTracking(ByVal obj As Object) - Dim injObj As CInjectedObject - injObj = New CInjectedObject(obj) - m_injectedObjects.Add(injObj) + If Not TypeOf (obj) Is CInjectedObject Then + Dim injObj As CInjectedObject + injObj = New CInjectedObject(obj) + m_injectedObjects.Add(injObj) + Else + m_injectedObjects.Add(obj) + End If End Sub Public Function ObjectIsTracked(ByVal obj) As Boolean @@ -2890,7 +2911,7 @@ Public Sub MarkForDeletion(ByVal obj As Object, ByVal deleteParents As Boolean) Dim injObj As CInjectedObject - injObj = m_injectedObjects.LocateObject(obj) + injObj = m_injectedObjects.Find(obj) If injObj Is Nothing Then 'Nothing to do Else @@ -2909,16 +2930,31 @@ Dim injObj As CInjectedObject m_inPersistChangesLoop = True 'Need to copy the injected object cache as saving objects may result - 'in new objects being added to the cache (via the object hierarchy) - Dim objectsToPersist As New CInjectedObjects + 'in the collection being modified which would break the for/each loop. + Dim objectsToPersist As New CInjectedObjectCache For Each de As DictionaryEntry In m_injectedObjects objectsToPersist.Add(de.Key, de.Value) Next + 'We will try to save/create objects first and then we will process deletes + 'This will prevent us trying to update objects that have been + 'autodeleted by another object (which would throw an exception) For Each de As DictionaryEntry In objectsToPersist injObj = de.Value - PersistChanges(injObj.ReferencedObject) + If Not injObj.MarkedForDeletion Then + PersistChanges(injObj.ReferencedObject) + End If + Next + For Each de As DictionaryEntry In objectsToPersist + injObj = de.Value + If injObj.MarkedForDeletion And injObj.Persistent Then + PersistChanges(injObj.ReferencedObject) + End If Next m_inPersistChangesLoop = False + For Each obj As CInjectedObject In m_objectsToDelete + m_injectedObjects.Remove(obj) + Next + m_objectsToDelete.Clear() Me.commit() Catch ex As Exception m_inPersistChangesLoop = False @@ -2933,20 +2969,23 @@ 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 ckey As CCacheKey Dim savedKeys As New ArrayList - injObj = m_injectedObjects.LocateObject(obj) - If injObj Is Nothing Then - injObj = New CInjectedObject(obj) - End If + 'If for some reason the object isn't being tracked for changes yet, we will start + 'tracking it now. + injObj = LocateOrCacheInjObject(obj) If injObj.MarkedForDeletion Then deleteObject(injObj, injObj.WillDeleteParents) If Not m_inPersistChangesLoop Then - m_injectedObjects.Remove(obj) + For Each xobj As CInjectedObject In m_objectsToDelete + m_injectedObjects.Remove(xobj) + Next + m_objectsToDelete.Clear() End If Else queue = getObjectsToSave(injObj, True, checkAssociationsRecursively) @@ -2954,17 +2993,23 @@ If queue.Count > 0 Then startTransaction() Do While queue.Count > 0 - value = queue.Dequeue() + qObject = queue.Dequeue() Try - ckey = New CCacheKey(value) - If savedKeys.Contains(ckey) Then - 'object was already saved (could be new object referenced by multiple other new objects) - Debug.WriteLine("The object with key " & ckey.ToString & " was already saved once") + If GetType(CAssociationObject).IsInstanceOfType(qObject) Then + saveAssociationObject(qObject) Else - saveObject(value) - 'Recalculate key value - required when identity columns are used + value = qObject ckey = New CCacheKey(value) - savedKeys.Add(ckey) + If savedKeys.Contains(ckey) Then + 'object was already saved (could be new object referenced by multiple other new objects) + Debug.WriteLine("The object with key " & ckey.ToString & " was already saved once") + Else + saveObject(value) + 'Recalculate key value - required when identity columns are used + ckey = New CCacheKey(value) + savedKeys.Add(ckey) + End If + value.IsDirty = False End If Catch ex As Exception 'After an error remove the cached object so that the next retrieve @@ -2974,25 +3019,24 @@ rollback() Throw New SaveException(ex.Message, ex) End Try - value.IsDirty = False Loop commit() End If End If End Sub - Friend Property InjectedObjects() As CInjectedObjects + Friend Property InjectedObjects() As CInjectedObjectCache Get Return m_injectedObjects End Get - Set(ByVal Value As CInjectedObjects) + Set(ByVal Value As CInjectedObjectCache) m_injectedObjects = Value End Set End Property Friend Sub InitPerformanceCounters() Try - If Not PerformanceCounterCategory.Exists("AtomsFramework") Then + If Not PerformanceCounterCategory.Exists("Atoms.Framework") Then Dim CCDC As New CounterCreationDataCollection @@ -3057,22 +3101,22 @@ CCDC.Add(BaseAvgOpTimeCount64) ' Create the category. - PerformanceCounterCategory.Create("AtomsFramework", "Performance Counters for the AtomsFramework", CCDC) + PerformanceCounterCategory.Create("Atoms.Framework", "Performance Counters for the Atoms.Framework", CCDC) End If Dim instanceName As String instanceName = System.Diagnostics.Process.GetCurrentProcess.ProcessName ' Create the counters. - PCSQLHits = New PerformanceCounter("AtomsFramework", "PCSQLHits", False) - PCCacheHits = New PerformanceCounter("AtomsFramework", "PCCacheHits", False) - PCInserts = New PerformanceCounter("AtomsFramework", "PCInserts", False) - PCUpdates = New PerformanceCounter("AtomsFramework", "PCUpdates", False) - PCReads = New PerformanceCounter("AtomsFramework", "PCReads", False) - PCDeletes = New PerformanceCounter("AtomsFramework", "PCDeletes", False) - PCCriteria = New PerformanceCounter("AtomsFramework", "PCCriteria", False) - PCCacheSize = New PerformanceCounter("AtomsFramework", "PCCacheSize", False) - PCAverageTime = New PerformanceCounter("AtomsFramework", "PCAverageTime", False) - PCAverageTimeBase = New PerformanceCounter("AtomsFramework", "PCAverageTimeBase", False) + PCSQLHits = New PerformanceCounter("Atoms.Framework", "PCSQLHits", False) + PCCacheHits = New PerformanceCounter("Atoms.Framework", "PCCacheHits", False) + PCInserts = New PerformanceCounter("Atoms.Framework", "PCInserts", False) + PCUpdates = New PerformanceCounter("Atoms.Framework", "PCUpdates", False) + PCReads = New PerformanceCounter("Atoms.Framework", "PCReads", False) + PCDeletes = New PerformanceCounter("Atoms.Framework", "PCDeletes", False) + PCCriteria = New PerformanceCounter("Atoms.Framework", "PCCriteria", False) + PCCacheSize = New PerformanceCounter("Atoms.Framework", "PCCacheSize", False) + PCAverageTime = New PerformanceCounter("Atoms.Framework", "PCAverageTime", False) + PCAverageTimeBase = New PerformanceCounter("Atoms.Framework", "PCAverageTimeBase", False) PCSQLHits.RawValue = 0 PCCacheHits.RawValue = 0 @@ -3090,14 +3134,15 @@ End Try End Sub - Public Shared Sub CopyCollections(ByVal fromObject As IPersistableObject, ByRef toObject As IPersistableObject) - Dim t, iEnumerableType, iListType, iDicType As Type Dim fromColl, toColl, collItem As Object + Public Shared Sub CopyCollections(ByVal fromObject As Object, ByRef toObject As Object) + Dim t, iEnumerableType, iListType, iDicType As Type + Dim fromColl, toColl, collItem As Object Dim il As IList Dim id As IDictionary Dim f, fields() As FieldInfo Dim value As Object - t = fromObject.GetObjectType + t = fromObject.GetType fields = t.GetFields(BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public) For Each f In fields iListType = f.FieldType.GetInterface("IList", True) @@ -3106,18 +3151,19 @@ Dim ICloneType As Type = f.FieldType.GetInterface("ICloneable", True) If Not ICloneType Is Nothing Then 'Getting the ICloneable interface from the object. - If Not f.GetValue(fromObject.GetSourceObject) Is Nothing Then - Dim IClone As ICloneable = CType(f.GetValue(fromObject.GetSourceObject), ICloneable) + If Not f.GetValue(fromObject) Is Nothing Then + Dim IClone As ICloneable = CType(f.GetValue(fromObject), ICloneable) toColl = IClone.Clone() Else toColl = Nothing End If Else - fromColl = f.GetValue(fromObject.GetSourceObject) + fromColl = f.GetValue(fromObject) If Not fromColl Is Nothing Then 'If the field doesn't support the ICloneable interface then just set it. t = f.FieldType - toColl = Activator.CreateInstance(t) 'need to copy references one-by-one + toColl = Activator.CreateInstance(t) + 'need to copy references one-by-one 'Also neeed to connect event handlers of new collection to new object based 'on event connections of the old collection and the old object Dim fColl, fieldsColl() As FieldInfo @@ -3134,7 +3180,7 @@ delArray = d.GetInvocationList For Each d In delArray If Not d.Target.GetType.GetInterface("IPersistableObject") Is Nothing Then - If CType(d.Target, IPersistableObject).Equals(fromObject.GetSourceObject) Then + If CType(d.Target, IPersistableObject).Equals(fromObject) Then newD = MulticastDelegate.CreateDelegate(fColl.FieldType, toObject, d.Method.Name) If collDel Is Nothing Then collDel = newD @@ -3169,7 +3215,15 @@ toColl = Nothing End If End If - f.SetValue(toObject.GetSourceObject, toColl) - End If Next + If Not toColl Is Nothing AndAlso f.FieldType Is GetType(CPersistentCollection) OrElse f.FieldType.IsSubclassOf(GetType(CPersistentCollection)) Then + Dim c As CPersistentCollection + c = CType(toColl, CPersistentCollection) + If Not c.ContainerObject Is Nothing AndAlso c.ContainerObject.Equals(fromObject) Then + c.ContainerObject = toObject + End If + End If + f.SetValue(toObject, toColl) + End If + Next End Sub End Class \ No newline at end of file Index: CCacheEntry.vb =================================================================== RCS file: /cvsroot/jcframework/dotnet/CCacheEntry.vb,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- CCacheEntry.vb 14 Feb 2005 02:23:10 -0000 1.29 +++ CCacheEntry.vb 28 Feb 2005 23:07:43 -0000 1.30 @@ -4,7 +4,7 @@ Imports System.Reflection '''----------------------------------------------------------------------------- -''' Project : AToMSFramework +''' Project : Atoms.Framework ''' Class : CCacheEntry ''' '''----------------------------------------------------------------------------- @@ -132,62 +132,6 @@ m_object = m_objectCopyAtTransactionStart End Sub - ' Public Sub CopyCollections() - ' Dim t, iEnumerableType, iListType, iDicType As Type ' Dim coll, obj As Object - ' Dim il As IList - ' Dim id As IDictionary - ' Dim f, fields() As FieldInfo - ' Dim value As Object - - ' 'We must precopy this collection into the collection copy ' 'A simple assignment would just copy a reference to the colletion, while ' 'we need to copy the collection itself, so that adding/removing elements ' 'of the original won't effect the copy - ' m_collectionCollection = New Specialized.HybridDictionary ' t = m_object.GetObjectType - ' fields = t.GetFields(BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public) - ' For Each f In fields - ' iListType = f.FieldType.GetInterface("IList", True) - ' iDicType = f.FieldType.GetInterface("IDictionary", True) - ' If Not iListType Is Nothing OrElse Not iDicType Is Nothing Then - ' Dim ICloneType As Type = f.FieldType.GetInterface("ICloneable", True) - ' If Not ICloneType Is Nothing Then - ' 'Getting the ICloneable interface from the object. - ' If Not f.GetValue(m_object.GetSourceObject) Is Nothing Then - ' Dim IClone As ICloneable = CType(f.GetValue(m_object.GetSourceObject), ICloneable) - ' coll = IClone.Clone() - ' Else - ' coll = Nothing - ' End If - ' Else - ' If Not f.GetValue(m_object.GetSourceObject) Is Nothing Then - ' 'If the field doesn't support the ICloneable interface then just set it. - ' coll = Activator.CreateInstance(f.FieldType) ' 'need to copy references one-by-one - ' If Not iListType Is Nothing Then - ' il = CType(coll, IList) - ' For Each obj In f.GetValue(m_object.GetSourceObject) - ' il.Add(obj) - ' Next - ' Else - ' id = CType(coll, IDictionary) - ' For Each de As DictionaryEntry In f.GetValue(m_object.GetSourceObject) - ' id.Add(de.Key, de.Value) - ' Next - ' End If - ' Else - ' coll = Nothing - ' End If - ' End If - ' m_collectionCollection.Add(f.Name, coll) ' End If ' Next - 'End Sub - - 'Public Sub RestoreCollections() - ' Dim t, iEnumerableType, iListType, iDicType As Type ' Dim f, fields() As FieldInfo - ' t = m_object.GetObjectType - ' fields = t.GetFields(BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public) - ' For Each f In fields - ' iListType = f.FieldType.GetInterface("IList", True) - ' iDicType = f.FieldType.GetInterface("IDictionary", True) - ' If Not iListType Is Nothing OrElse Not iDicType Is Nothing Then - ' 'We must restore this collection from the collection copy ' 'Just use a straight value assignment - no need to worry about cloning ' f.SetValue(m_object.GetSourceObject, m_collectionCollection.Item(f.Name)) ' End If ' Next - 'End Sub - Public Sub New(ByVal lifetime As Double) m_expiryTime = DateAdd(DateInterval.Minute, lifetime, Now) End Sub @@ -274,7 +218,7 @@ End Class '''----------------------------------------------------------------------------- -''' Project : AToMSFramework +''' Project : Atoms.Framework ''' Class : CCacheKey ''' '''----------------------------------------------------------------------------- @@ -482,7 +426,7 @@ Return m_hashCode End Function - Private Sub CalculateHashCode(ByVal cachedObject) + Private Sub CalculateHashCode(ByVal cachedObject As Object) Dim i As Long Dim count As Integer Dim obj As Object @@ -552,7 +496,7 @@ End Class '''----------------------------------------------------------------------------- -''' Project : AToMSFramework +''' Project : Atoms.Framework ''' Class : CCacheCollection ''' '''----------------------------------------------------------------------------- @@ -956,7 +900,6 @@ For Each x In Me ce = x.Value If ce.PersistentObject.GetClassMap.RelationalDatabase Is reldb Then - 'ce.CopyCollections() ce.CopyObject() End If Next Index: CMultiRetrieveCriteria.vb =================================================================== RCS file: /cvsroot/jcframework/dotnet/CMultiRetrieveCriteria.vb,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- CMultiRetrieveCriteria.vb 28 Oct 2004 00:16:12 -0000 1.18 +++ CMultiRetrieveCriteria.vb 28 Feb 2005 23:07:44 -0000 1.19 @@ -4,7 +4,7 @@ Imports System.Collections.Specialized '''----------------------------------------------------------------------------- -''' Project : AToMSFramework +''' Project : Atoms.Framework ''' Class : CMultiRetrieveCriteria ''' '''----------------------------------------------------------------------------- @@ -140,7 +140,7 @@ Me.New() Dim injObj As CInjectedObject Dim pbroker As CPersistenceBroker = modPersistenceBrokerSingleton.getPersistenceBrokerInstance - injObj = pbroker.LocateOrCreateInjObject(obj) + injObj = pbroker.getInjectedObject(obj) Me.addObjectToJoin(injObj, Nothing, "") Me.ClassMap = pbroker.getClassMap(obj.GetType) m_joins = New CJoin(Me.ClassMap, "t1") Index: CInjectedObjects.vb =================================================================== RCS file: /cvsroot/jcframework/dotnet/CInjectedObjects.vb,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- CInjectedObjects.vb 25 Oct 2004 07:12:31 -0000 1.3 +++ CInjectedObjects.vb 28 Feb 2005 23:07:44 -0000 1.4 @@ -1,3 +1,5 @@ +Imports System.Threading + 'Injected object keys are hashed on the object itself, not the value of the object '(unlike the persistence brokers cache which works via key values) @@ -11,7 +13,6 @@ NewInjObj(CType(obj, CInjectedObject)) Else m_keyvalues = New Collection - m_hashCode = obj.GetHashCode Dim injObj As New CInjectedObject(obj) populateKey(injObj) End If @@ -20,9 +21,7 @@ Public Sub NewInjObj(ByVal injobj As CInjectedObject) m_keyvalues = New Collection If injobj.ReferencedObject Is Nothing Then - m_hashCode = 0 - Else - m_hashCode = injobj.ReferencedObject.GetHashCode + Throw New Exception("Cannot track null objects") End If populateKey(injobj) End Sub @@ -31,6 +30,31 @@ Return m_hashCode End Function + Private Sub CalculateHashCode() + Dim i As Long + Dim count As Integer + Dim obj As Object + Dim t As Type + i = m_type.Name.GetHashCode + count = 1 + For Each obj In m_keyvalues + If Not obj Is Nothing Then + If TypeOf obj Is Integer Then + i += CInt(obj).GetHashCode + ElseIf TypeOf obj Is String Then + i += CStr(obj).GetHashCode + ElseIf TypeOf obj Is Double Then + i += CDbl(obj).GetHashCode + Else + t = obj.GetType + i += t.Name.GetHashCode + End If + count += 1 + End If + Next + m_hashCode = CInt(i / count) + End Sub + Protected Sub populateKey(ByVal injObj As IPersistableObject) Dim cm As CClassMap Dim i As Short @@ -43,8 +67,12 @@ For i = 1 To cm.getKeySize am = cm.getKeyAttributeMap(i) x = injObj.GetValueByAttribute(am.Name) + If x Is Nothing Then + Throw New Exception("Cannot have null key values") + End If m_keyvalues.Add(x) Next + CalculateHashCode() End Sub Public Overloads Shared Function Equals(ByVal obj1 As Object, ByVal obj2 As Object) As Boolean @@ -57,13 +85,14 @@ End Function Public Overloads Overrides Function Equals(ByVal obj1 As Object) As Boolean - Dim flag As Boolean Dim i As Integer Dim key As CInjectedObjectKey - key = CType(obj1, CInjectedObjectKey) - flag = False + key = obj1 + If Not (Me.m_type Is key.m_type) Then + Return False + End If For i = 1 To m_keyvalues.Count - If Me.GetHashCode <> key.GetHashCode Then + If m_keyvalues(i) <> key.m_keyvalues(i) Then Return False End If Next @@ -97,17 +126,23 @@ End Class -Public Class CInjectedObjects +Public Class CInjectedObjectCache Inherits System.Collections.Hashtable + Private m_lastFoundKey As CInjectedObjectKey + Public Overloads Sub Add(ByVal obj As CInjectedObject) Dim injKey As CInjectedObjectKey If obj.ReferencedObject Is Nothing Then - Exit Sub + Throw New Exception("Cannot track null objects") End If - injKey = New CInjectedObjectKey(obj) + Try + injKey = New CInjectedObjectKey(obj) + Catch ex As Exception + Throw New Exception("Cannot track objects with blank keys") + End Try If Not (MyBase.Item(injKey) Is Nothing) Then Debug.WriteLine("Object: " & obj.GetObjectType.ToString & " is already tracked with key(s):" & vbCrLf & injKey.ToString) Else @@ -116,21 +151,9 @@ End If End Sub - Public Function LocateObject(ByVal obj As Object) As CInjectedObject - Dim injKey As CInjectedObjectKey - Dim injObj As CInjectedObject - injKey = New CInjectedObjectKey(obj) - If Not (MyBase.Item(injKey) Is Nothing) Then - injObj = CType(MyBase.Item(injKey), CInjectedObject) - Return injObj - Else - Return Nothing - End If - End Function - Public Overloads Function isTracked(ByVal obj As Object) As Boolean Dim injObj As CInjectedObject - injObj = LocateObject(obj) + injObj = Find(obj) If injObj Is Nothing Then Return False Else @@ -139,20 +162,24 @@ End Function Public Overloads Function Exists(ByVal obj As CInjectedObject, ByVal useFindAttributes As Boolean) As Boolean - If FindByValue(obj, useFindAttributes) Is Nothing Then + If Find(obj, useFindAttributes) Is Nothing Then Return False Else Return True End If End Function - Public Overloads Function FindByValue(ByVal obj As Object) As CInjectedObject + Public Overloads Function Find(ByVal obj As Object) As CInjectedObject + Return Find(obj, False) + End Function + + Public Overloads Function Find(ByVal obj As Object, ByVal useFindAttributes As Boolean) As CInjectedObject Dim injObj As CInjectedObject injObj = New CInjectedObject(obj) - Return FindByValue(injObj, False) + Return Find(injObj, useFindAttributes) End Function - Public Overloads Function FindByValue(ByVal obj As CInjectedObject, ByVal useFindAttributes As Boolean) As CInjectedObject + Public Overloads Function Find(ByVal obj As CInjectedObject, ByVal useFindAttributes As Boolean) As CInjectedObject Dim injObj As CInjectedObject Dim x As DictionaryEntry Dim attrmap As CAttributeMap @@ -163,6 +190,10 @@ Dim interval As Double Dim ikey As CInjectedObjectKey + 'We cannot use the dictionary key to find an object as changes to the key attributes + 'of an object will result in a different dictionary key being generated and an + 'we won't be able to find the object, even though it exists. + cm = obj.getClassMap 'We only check for objects of the same type @@ -174,29 +205,31 @@ t = injObj.GetObjectType If t Is obj.GetObjectType Or t.IsSubclassOf(obj.GetObjectType) Then found = True - If useFindAttributes Then - For i = 1 To cm.getFindSize - attrmap = CType(cm.FindAttributeMaps(i), CAttributeMap) - If Not obj.getValueByAttribute(attrmap.Name).Equals(injObj.getValueByAttribute(attrmap.Name)) Then - found = False - Exit For - End If - Next i - Else - For i = 1 To cm.getKeySize - attrmap = CType(cm.KeyAttributeMaps(i), CAttributeMap) - If Not obj.getValueByAttribute(attrmap.Name).Equals(injObj.getValueByAttribute(attrmap.Name)) Then - found = False - Exit For - End If - Next i - End If + Try + If useFindAttributes Then + For i = 1 To cm.getFindSize + attrmap = CType(cm.FindAttributeMaps(i), CAttributeMap) + If Not obj.getValueByAttribute(attrmap.Name).Equals(injObj.getValueByAttribute(attrmap.Name)) Then + found = False + Exit For + End If + Next i + Else + For i = 1 To cm.getKeySize + attrmap = CType(cm.KeyAttributeMaps(i), CAttributeMap) + If Not obj.getValueByAttribute(attrmap.Name).Equals(injObj.getValueByAttribute(attrmap.Name)) Then + found = False + Exit For + End If + Next i + End If + Catch ex As Exception + found = False + End Try If found Then - 'If ce.TransactionType = CCacheEntry.CacheTransaction.Deleted Then - ' Return Nothing - 'End If ikey = CType(x.Key, CInjectedObjectKey) Debug.WriteLine([String].Format("Injection Cache - getting object from cache. Key..." & vbCrLf & ikey.ToString)) + m_lastFoundKey = ikey Return injObj End If End If @@ -204,12 +237,19 @@ Return Nothing End Function - Public Overloads Sub Remove(ByVal obj As Object) + Public Overloads Sub Remove(ByVal obj As CInjectedObject) If obj Is Nothing Then Exit Sub End If - Dim injkey As New CInjectedObjectKey(obj) - MyBase.Remove(injkey) + Try + 'If key values have changed removing the object means we cannot just + 'generate an injection key and delete using the key - we must find it first + 'then delete it. + Dim injObj As CInjectedObject = Me.Find(obj, False) + If injObj Is Nothing Then Return + MyBase.Remove(m_lastFoundKey) + Catch + End Try End Sub Public Overrides Function ToString() As String @@ -233,4 +273,5 @@ outString &= ">>>> END TRACKED OBJECTS DUMP <<<<" Return outString End Function -End Class \ No newline at end of file +End Class + Index: CClassMap.vb =================================================================== RCS file: /cvsroot/jcframework/dotnet/CClassMap.vb,v retrieving revision 1.50 retrieving revision 1.51 diff -u -d -r1.50 -r1.51 --- CClassMap.vb 11 Feb 2005 02:51:35 -0000 1.50 +++ CClassMap.vb 28 Feb 2005 23:07:43 -0000 1.51 @@ -6,7 +6,7 @@ Imports System.Runtime.Remoting '''----------------------------------------------------------------------------- -''' Project : AToMSFramework +''' Project : Atoms.Framework ''' Class : CClassMap ''' '''----------------------------------------------------------------------------- @@ -1407,7 +1407,7 @@ If checkForDuplicateAttributes Then Try 'If Not classMapToCheck.getAttributeMapByString(AttrMap.Name, False) Is Nothing Then - If Not classMapToCheck.getAttributeMapByString(AttrMap.Name, True) Is Nothing Then + If Not classMapToCheck.getAttributeMapByString(AttrMap.Name, False) Is Nothing Then skipAttribute = True End If Catch @@ -1502,7 +1502,7 @@ If checkForDuplicateAttributes Then Try 'If Not classMapToCheck.getAttributeMapByString(AttrMap.Name, False) Is Nothing Then - If Not classMapToCheck.getAttributeMapByString(AttrMap.Name, True) Is Nothing Then + If Not classMapToCheck.getAttributeMapByString(AttrMap.Name, False) Is Nothing Then skipAttribute = True End If Catch @@ -2106,7 +2106,7 @@ ip = CType(obj, IPersistableObject) Catch ex As Exception pbroker = getPersistenceBrokerInstance() - pbroker.StartTracking(obj) + 'pbroker.StartTracking(obj) ip = pbroker.getInjectedObject(obj) End Try Return ip @@ -2122,7 +2122,7 @@ ip = CType(obj, IPersistableObject) Catch ex As Exception pbroker = getPersistenceBrokerInstance() - pbroker.StartTracking(obj) + 'pbroker.StartTracking(obj) ip = pbroker.getInjectedObject(obj) End Try Return ip Index: CCursor.vb =================================================================== RCS file: /cvsroot/jcframework/dotnet/CCursor.vb,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- CCursor.vb 9 Nov 2004 11:46:04 -0000 1.14 +++ CCursor.vb 28 Feb 2005 23:07:44 -0000 1.15 @@ -2,24 +2,24 @@ Option Explicit On '''----------------------------------------------------------------------------- -''' Project : AToMSFramework +''' Project : Atoms.Framework ''' Class : CCursor ''' '''----------------------------------------------------------------------------- ''' <summary> ''' Holds the current position within a CResultSet. ''' </summary> -''' <remarks>The CCursor class references an position within a <see cref="T:AToMSFramework.CResultset"/> -''' that has been returned by either a <see cref="T:AToMSFramework.CRetrieveCriteria"/> or -''' a <see cref="T:AToMSFramework.CMultiRetrieveCriteria"/>. -''' <para>Objects can be instantiated from a CCursor using the <see cref="M:AToMSFramework.CCursor.LoadObject"/> method +''' <remarks>The CCursor class references an position within a <see cref="T:Atoms.Framework.CResultset"/> +''' that has been returned by either a <see cref="T:Atoms.Framework.CRetrieveCriteria"/> or +''' a <see cref="T:Atoms.Framework.CMultiRetrieveCriteria"/>. +''' <para>Objects can be instantiated from a CCursor using the <see cref="M:Atoms.Framework.CCursor.LoadObject"/> method ''' and will either be proxy objects or ''' full objects depending on the way the retrieve criteria was used.</para> ''' <para>A CCursor should only be created through the perform methods of the various ''' retrieve criteria, and once created it will contain information on the data retrieved.</para> -''' <para>Use the <see cref="M:AToMSFramework.CCursor.hasElements"/> method to determine -''' if the cursor contains any data, and use the <see cref="M:AToMSFramework.CCursor.previousCursor"/> and -''' <see cref="M:AToMSFramework.CCursor.nextCursor"/> methods to moved the cursor to the previous or next +''' <para>Use the <see cref="M:Atoms.Framework.CCursor.hasElements"/> method to determine +''' if the cursor contains any data, and use the <see cref="M:Atoms.Framework.CCursor.previousCursor"/> and +''' <see cref="M:Atoms.Framework.CCursor.nextCursor"/> methods to moved the cursor to the previous or next ''' record in the result set.</para> ''' </remarks> ''' <history> @@ -254,7 +254,7 @@ Dim pbroker As CPersistenceBroker = modPersistenceBrokerSingleton.getPersistenceBrokerInstance Dim injObj As CInjectedObject - injObj = pbroker.LocateOrCreateInjObject(obj) + injObj = pbroker.getInjectedObject(obj) If Not m_parentCriteria Is Nothing Then If m_parentCriteria.GetType Is GetType(CMultiRetrieveCriteria) Then mr = m_parentCriteria @@ -461,7 +461,7 @@ Dim pbroker As CPersistenceBroker = modPersistenceBrokerSingleton.getPersistenceBrokerInstance Dim injObj As CInjectedObject - injObj = pbroker.LocateOrCreateInjObject(obj) + injObj = pbroker.getInjectedObject(obj) If Not m_parentCriteria Is Nothing Then If m_parentCriteria.GetType Is GetType(CMultiRetrieveCriteria) Then cm = m_parentCriteria Index: CInjectedObject.vb =================================================================== RCS file: /cvsroot/jcframework/dotnet/CInjectedObject.vb,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- CInjectedObject.vb 14 Feb 2005 02:23:10 -0000 1.13 +++ CInjectedObject.vb 28 Feb 2005 23:07:44 -0000 1.14 @@ -29,8 +29,7 @@ Public Sub New(ByVal obj As Object) MyBase.New() m_object = obj - m_originalObject = Activator.CreateInstance(m_object.GetType) - 'ReplaceValues(m_object, m_originalObject) + m_originalObject = Activator.CreateInstance(obj.GetType) End Sub Public Property ReferencedObject() As Object @@ -38,7 +37,7 @@ Return m_object End Get Set(ByVal Value As Object) - m_object = Value + m_object = New WeakReference(Value) End Set End Property @@ -102,92 +101,79 @@ End Sub Public Function getClassMap() As CClassMap Implements IPersistableObject.getClassMap - Dim ClassMap As CClassMap Dim tmpCMap As CClassMap - ClassMap = getClassMap(TypeName(m_object), m_object.GetType.FullName) - If ClassMap Is Nothing Then - '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 + If m_classmap Is Nothing Then + m_classmap = getClassMap(TypeName(m_object), m_object.GetType.FullName) + If m_classmap Is Nothing Then + '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 - ' get the super class map if the object has multi-level inheritance - For n = 0 To interfaces.Length - 1 - ClassMap = getClassMap(interfaces(n).Name, interfaces(n).FullName) - If (Not ClassMap Is Nothing) AndAlso ClassMap.SuperClass Is Nothing Then - super = 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 + '----------------------------------------- + Dim n, m As Integer + Dim super As CClassMap - '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 - ClassMap = super + ' 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 - interfaces(m) = Nothing + If interfaces.Length > 1 Then + interfaces(m) = Nothing + End If + Exit For + End If + Next - If interfaces(0) Is Nothing Then - ClassMap = tmpCMap - Exit While + '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 - n = 0 Else n = n + 1 End If - Else - n = n + 1 - End If - End While - '----------------------------------------- - - 'For Each intType In interfaces - ' tmpCMap = getClassMap(intType.Name, intType.FullName) - ' 'If this class has children, iterate through other class maps to see if - ' 'the object inherits a child class, otherwise we can get the wrong class map - ' 'returned. - ' If Not tmpCMap Is Nothing Then - ' If ClassMap Is Nothing Then ClassMap = tmpCMap - ' If tmpCMap.ChildrenMaps.Count = 0 Then - ' ClassMap = tmpCMap - ' Exit For - ' End If - ' End If - 'Next - End If - If (ClassMap Is Nothing) Then - Throw New NoClassMapException("No class map for " & m_object.GetType.FullName) + 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 - Return ClassMap + Return m_classmap End Function Private Function getClassMap(ByVal name As String, ByVal fullname As String) As CClassMap - Dim ClassMap As CClassMap - Dim persistenceBroker As CPersistenceBroker - persistenceBroker = getPersistenceBrokerInstance() - ClassMap = persistenceBroker.getClassMap(name) - If ClassMap Is Nothing Then - ClassMap = persistenceBroker.getClassMap(fullname) - End If - If (ClassMap Is Nothing) Then - Return Nothing + If m_classmap Is Nothing Then + Dim persistenceBroker As CPersistenceBroker + persistenceBroker = getPersistenceBrokerInstance() + m_classmap = persistenceBroker.getClassMap(name) + If m_classmap Is Nothing Then + m_classmap = persistenceBroker.getClassMap(fullname) + End If + If (m_classmap Is Nothing) Then + Return Nothing + End If End If - Return ClassMap + Return m_classmap End Function Public Function GetObjectType() As Type Implements IPersistableObject.GetObjectType @@ -307,32 +293,58 @@ If Not sourceObject.GetType Is targetObject.GetType Then Return False End If - Dim f, fields() As FieldInfo + + Dim cmap As CClassMap Dim value As Object, value1 As Object - 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) + + cmap = Me.getClassMap() + + 'Do equality checks only on attributes that will be persisted + 'Everything else is ignorable since it's only the database mapped fields + 'that are important + While Not cmap Is Nothing + For Each att As CAttributeMap In m_classmap.AttributeMaps + If Not att.ColumnMap Is Nothing Then + value = getValueByAttribute(att.Name) + value1 = getOriginalValueByAttribute(att.Name) 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 + Next + If Not cmap.SuperClass Is Nothing Then + cmap = cmap.SuperClass + Else + cmap = Nothing + End If + End While Return False + + '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 @@ -558,7 +570,7 @@ injobj = CType(Me.MemberwiseClone, CInjectedObject) 'Because memberwise clone only reference copies collections we should also 'copy the collections as well, since failing to do so can corrupt the cache. - CPersistenceBroker.CopyCollections(Me, injobj) + CPersistenceBroker.CopyCollections(Me.GetSourceObject, injobj.GetSourceObject) Return injobj End Function Index: CPersistentObject.vb =================================================================== RCS file: /cvsroot/jcframework/dotnet/CPersistentObject.vb,v retrieving revision 1.55 retrieving revision 1.56 diff -u -d -r1.55 -r1.56 --- CPersistentObject.vb 14 Feb 2005 02:23:11 -0000 1.55 +++ CPersistentObject.vb 28 Feb 2005 23:07:54 -0000 1.56 @@ -6,7 +6,7 @@ Imports System.Runtime.Remoting '''----------------------------------------------------------------------------- -''' Project : AToMSFramework +''' Project : Atoms.Framework ''' Class : CPersistentObject ''' '''----------------------------------------------------------------------------- @@ -39,11 +39,11 @@ Private m_originalModDate, m_blankDate As Date Private m_cacheExpiry As Double Private m_associationsLoaded As Boolean - Private m_guid As Guid - Private m_isLoading As Boolean = False + Private m_guid As Guid + Private m_isLoading As Boolean = False Private m_isQueued As Boolean = False Private m_checkingAssociations As Boolean - Private m_isNew As Boolean + Private m_isNew As Boolean Private m_editing As Boolean <NonSerialized()> Private m_classmap As CClassMap @@ -181,7 +181,7 @@ ''' </summary> ''' <value>Boolean indicating that the object has been modified</value> ''' <remarks>This flag must be set by the object whenever one of it's properties changes. - ''' Failing to do so will prevent the AtomsFramework from updating the database when + ''' Failing to do so will prevent the Atoms.Framework from updating the database when ''' the save method is performed. ''' <para>When an object is initially received this flag will be False.</para> ''' <para>Note: Changes to objects in a CPersistentCollection can result in this flag being set.</para></remarks> @@ -603,7 +603,7 @@ ''' <returns>An object of the subclasses type</returns> ''' <remarks>This is used internally by the framework and must be implemented by objects that ''' inherit the CPersistentObject. A typical example of this would be - ''' <code> Public Overrides Function getNewObject() As AToMSFramework.CPersistentObject + ''' <code> Public Overrides Function getNewObject() As Atoms.Framework.CPersistentObject ''' Return New CEmployee ''' End Function</code> ''' </remarks> @@ -643,7 +643,7 @@ Return True End If Next - Return False + Return False End Function '''----------------------------------------------------------------------------- @@ -675,7 +675,7 @@ Return CallByName(o, propertyName, CallType.Get) End If Catch err As Exception - Throw New Exception("getCollectionByAttribute failed for class " & me.getclassmap.name & " attribute: " & " " & pname, err) + Throw New Exception("getCollectionByAttribute failed for class " & Me.getclassmap.name & " attribute: " & " " & pname, err) End Try End Function @@ -1122,15 +1122,15 @@ Static eventRaised As Boolean If m_persistent = True Then m_modifiedDate = Now 'Only set modified if the object is already persistent - 'Set milliseconds to zero to avoid issues with millisecond inconsistencies in SQL db's + 'Set milliseconds to zero to avoid issues with millisecond inconsistencies in MSSQL db's m_modifiedDate = m_modifiedDate.AddMilliseconds(-m_modifiedDate.Millisecond) - If m_dirty = False Then - If Not eventRaised Then - 'Was getting stack overflow with direct many-to-many associations due to circular event raising - eventRaised = True - RaiseEvent MarkedAsDirty(Me, New EventArgs) - eventRaised = False - End If + End If + If m_dirty = False Then + If Not eventRaised Then + 'Was getting stack overflow with direct many-to-many associations due to circular event raising + eventRaised = True + RaiseEvent MarkedAsDirty(Me, New EventArgs) + eventRaised = False End If End If m_dirty = True @@ -1240,12 +1240,7 @@ Dim obj As CPersistentObject obj = Me.getClassMap.CreateObjectInstance obj.ReplaceWith(Me) - 'obj = CType(Me.MemberwiseClone, CPersistentObject) - 'Because memberwise clone only reference copies collections we should also - 'copy the collections as well, since failing to do so can corrupt the cache. - 'This will also connect events from the collections to the new object based on - 'existing event handlers in "Me" - 'CPersistenceBroker.CopyCollections(Me, obj) Return obj + Return obj End Function '''----------------------------------------------------------------------------- @@ -1394,12 +1389,12 @@ Public Overridable Function getAll(ByVal pOrderCol As Collection, ByVal pOrderAscCol As Collection) As CPersistentCollection Dim obj As Object Dim obCol As CPersistentCollection - Dim obRC As AToMSFramework.CRetrieveCriteria - Dim obCursor As AToMSFramework.CCursor + Dim obRC As CRetrieveCriteria + Dim obCursor As CCursor Dim inIndex As Integer Dim boAscend As Boolean - obRC = New AToMSFramework.CRetrieveCriteria + obRC = New CRetrieveCriteria obRC.ClassMap = Me.getClassMap obRC.ReturnFullObjects = True @@ -1795,7 +1790,7 @@ ''' </history> ''' ----------------------------------------------------------------------------- <Browsable(False), EditorBrowsable(EditorBrowsableState.Advanced)> _ - Public Overridable ReadOnly Property [Error]() As String Implements System.ComponentModel.IDataErrorInfo.Error + Public Overridable ReadOnly Property [Error]() As String Implements System.ComponentModel.IDataErrorInfo.Error Get If Me.IsValid Then Return "" |