Index: Source/Entities/EntityData.cst =================================================================== --- Source/Entities/EntityData.cst (revision 559) +++ Source/Entities/EntityData.cst (working copy) @@ -30,7 +30,7 @@ /// [EditorBrowsable(EditorBrowsableState.Never)] [Serializable] - internal protected class <%=structName%> : ICloneable + internal protected class <%=structName%> : ICloneable, ICloneableEx { #region Variable Declarations private EntityState currentEntityState = EntityState.Added; @@ -191,6 +191,81 @@ return _tmp; } + /// + /// Creates a new object that is a copy of the current instance. + /// + /// A new object that is a copy of this instance. + public object Clone(IDictionary existingCopies) + { + if (existingCopies == null) + existingCopies = new Hashtable(); + + <%=structName%> _tmp = new <%=structName%>(); + + <% for(int i=0; i + _tmp.<%=GetPropertyName(SourceTable.PrimaryKey.MemberColumns[i])%> = this.<%=GetPropertyName(SourceTable.PrimaryKey.MemberColumns[i])%>; + <% if (!IsIdentityColumn(SourceTable.PrimaryKey.MemberColumns[i]) && !(IsComputed(SourceTable.PrimaryKey.MemberColumns[i]))) {%> + _tmp.<%=GetOriginalPropertyName(SourceTable.PrimaryKey.MemberColumns[i])%> = this.<%=GetOriginalPropertyName(SourceTable.PrimaryKey.MemberColumns[i])%>; + <% } %> + <% } %> + + <% for (int x=0; x < SourceTable.NonPrimaryKeyColumns.Count; x++) { %> + _tmp.<%= GetPropertyName(SourceTable.NonPrimaryKeyColumns[x]) %> = this.<%= GetPropertyName(SourceTable.NonPrimaryKeyColumns[x]) %>; + <% } %> + + #region Source Parent Composite Entities + <% if (IncludeGetListByFK) { %> + <% //Generate a Source property for each foreign key relation + System.Collections.ArrayList filled = new System.Collections.ArrayList(); + foreach(TableKeySchema tableKey in SourceTable.ForeignKeys) + { + // related table must be in the selection + if (SourceTables.Contains(tableKey.PrimaryKeyTable)) { + string fkPropertyName = GetKeysName(tableKey.ForeignKeyMemberColumns); + + if(filled.Contains(fkPropertyName)) + continue; + + filled.Add(fkPropertyName); + + string pkClassName = GetClassName(tableKey.PrimaryKeyTable.Name); + + %> + if (this.<%=fkPropertyName%>Source != null && existingCopies.Contains(this.<%=fkPropertyName%>Source)) + _tmp.<%=fkPropertyName%>Source = existingCopies[this.<%=fkPropertyName%>Source] as <%= pkClassName %>; + else + _tmp.<%=fkPropertyName%>Source = MakeCopyOf(this.<%=fkPropertyName%>Source, existingCopies) as <%= pkClassName %>; + <% } //end if in SourceTables + } //end for each FK + }// IncludeGetListByFK%> + #endregion + + #region Child Collections + <% if (IncludeRelations){ + int ctr = 0; + foreach(CollectionInfo item in GetChildrenCollections(SourceTable, SourceTables).Values) { + if (ctr == 0) + Response.Write("\t\t\t//deep copy nested objects" + Environment.NewLine); + ctr++; + + string typeName = ""; + if (item.CollectionRelationshipType == MoM.Templates.CommonSqlCode.RelationshipType.OneToOne) + typeName = item.TypeName; + else + typeName = item.CollectionTypeName; + %> + _tmp.<%= item.PropertyNameUnique %> = (<%= typeName %>) MakeCopyOf(this.<%=item.PropertyNameUnique %>, existingCopies); + <% }//end foreach CollectionInfo + }//end if IncludeRelations + %> + #endregion Child Collections + + //EntityState + _tmp.EntityState = this.EntityState; + + return _tmp; + } + #endregion Clone Method /// @@ -362,3 +437,4 @@ } + Index: Source/Entities/EntityInstanceBase.generated.cst =================================================================== --- Source/Entities/EntityInstanceBase.generated.cst (revision 559) +++ Source/Entities/EntityInstanceBase.generated.cst (working copy) @@ -91,7 +91,7 @@ <% } %> [Serializable, DataObject] [CLSCompliant(true)] - public abstract partial class <%=abstractClassName%> : EntityBase, <%=NameSpace%>.I<%= className %>, IEntityId<<%= keyClassName %>>, System.IComparable, System.ICloneable, IEditableObject, IComponent, INotifyPropertyChanged + public abstract partial class <%=abstractClassName%> : EntityBase, <%=NameSpace%>.I<%= className %>, IEntityId<<%= keyClassName %>>, System.IComparable, System.ICloneable, ICloneableEx, IEditableObject, IComponent, INotifyPropertyChanged { #region Variable Declarations @@ -513,37 +513,47 @@ /// /// Returns a Typed <%=className%> Entity /// - public virtual <%=className%> Copy() + protected virtual <%=className%> Copy(IDictionary existingCopies) { + if (existingCopies == null) + { + // This is the root of the tree to be copied! + existingCopies = new Hashtable(); + } + //shallow copy entity <%=className%> copy = new <%=className%>(); + existingCopies.Add(this, copy); copy.SuppressEntityEvents = true; <% for (int x=0; x < cols.Count; x++) { %> - copy.<%= GetPropertyName(cols[x]) %> = this.<%= GetPropertyName(cols[x]) %>; - <% if( cols[x].IsPrimaryKeyMember && !IsIdentityColumn(cols[x]) && !IsComputed(cols[x]) ) { %> - copy.<%= GetOriginalPropertyName(cols[x]) %> = this.<%= GetOriginalPropertyName(cols[x]) %>; + copy.<%= GetPropertyName(cols[x]) %> = this.<%= GetPropertyName(cols[x]) %>; + <% if( cols[x].IsPrimaryKeyMember && !IsIdentityColumn(cols[x]) && !IsComputed(cols[x]) ) { %> + copy.<%= GetOriginalPropertyName(cols[x]) %> = this.<%= GetOriginalPropertyName(cols[x]) %>; + <% } %> <% } %> - <% } %> <% if (IncludeGetListByFK) { %> - <% //Generate a Source property for each foreign key relation - System.Collections.ArrayList filled = new System.Collections.ArrayList(); - foreach(TableKeySchema tableKey in SourceTable.ForeignKeys) - { - // related table must be in the selection - if (SourceTables.Contains(tableKey.PrimaryKeyTable)) { - string fkPropertyName = GetKeysName(tableKey.ForeignKeyMemberColumns); + <% //Generate a Source property for each foreign key relation + System.Collections.ArrayList filled = new System.Collections.ArrayList(); + foreach(TableKeySchema tableKey in SourceTable.ForeignKeys) + { + // related table must be in the selection + if (SourceTables.Contains(tableKey.PrimaryKeyTable)) { + string fkPropertyName = GetKeysName(tableKey.ForeignKeyMemberColumns); - if(filled.Contains(fkPropertyName)) - continue; + if(filled.Contains(fkPropertyName)) + continue; + + filled.Add(fkPropertyName); - filled.Add(fkPropertyName); - - string pkClassName = GetClassName(tableKey.PrimaryKeyTable.Name); - %> - copy.<%=fkPropertyName%>Source = MakeCopyOf(this.<%=fkPropertyName%>Source) as <%= pkClassName %>; - <% } //end if in SourceTables - } //end for each FK + string pkClassName = GetClassName(tableKey.PrimaryKeyTable.Name); + %> + if (this.<%=fkPropertyName%>Source != null && existingCopies.Contains(this.<%=fkPropertyName%>Source)) + copy.<%=fkPropertyName%>Source = existingCopies[this.<%=fkPropertyName%>Source] as <%= pkClassName %>; + else + copy.<%=fkPropertyName%>Source = MakeCopyOf(this.<%=fkPropertyName%>Source, existingCopies) as <%= pkClassName %>; + <% } //end if in SourceTables + } //end for each FK }// IncludeGetListByFK%> <% @@ -560,13 +570,23 @@ else typeName = item.CollectionTypeName; %> - copy.<%= item.PropertyNameUnique %> = (<%= typeName %>) MakeCopyOf(this.<%=item.PropertyNameUnique %>); + copy.<%= item.PropertyNameUnique %> = (<%= typeName %>) MakeCopyOf(this.<%=item.PropertyNameUnique %>, existingCopies); <% }//end foreach CollectionInfo }//end if IncludeRelations %> copy.EntityState = this.EntityState; copy.SuppressEntityEvents = false; return copy; + } + + + + /// + /// Returns a Typed <%=className%> Entity + /// + public virtual <%=className%> Copy() + { + return this.Copy(null); } /// @@ -574,10 +594,18 @@ /// public object Clone() { - return this.Copy(); + return this.Copy(null); } /// + /// ICloneableEx.Clone() Member, returns the Shallow Copy of this entity. + /// + public object Clone(IDictionary existingCopies) + { + return this.Copy(existingCopies); + } + + /// /// Returns a deep copy of the child collection object passed in. /// public static object MakeCopyOf(object x) @@ -595,6 +623,29 @@ } /// + /// Returns a deep copy of the child collection object passed in. + /// + public static object MakeCopyOf(object x, IDictionary existingCopies) + { + if (x == null) + return null; + + if (x is ICloneableEx) + { + // Return a deep copy of the object + return ((ICloneableEx)x).Clone(existingCopies); + } + else if (x is ICloneable) + { + // Return a deep copy of the object + return ((ICloneable)x).Clone(); + } + else + throw new System.NotSupportedException("Object Does Not Implement the ICloneable or IClonableEx Interface."); + } + + + /// /// Returns a Typed <%=className%> Entity which is a deep copy of the current entity. /// public virtual <%=className%> DeepCopy() @@ -679,10 +730,11 @@ ///true if Object1 is a and has the same value as this instance; otherwise, false. public override bool Equals(object Object1) { - if (Object1 is <%=abstractClassName%>) - return Equals(this, (<%=abstractClassName%>)Object1); - else + // Cast exception if Object1 is null or DbNull + if (Object1 == null || Object1 == DBNull.Value) return false; + else + return Equals(this, (<%=abstractClassName%>)Object1); } /// Index: Source/Entities/IEntity.cst =================================================================== --- Source/Entities/IEntity.cst (revision 559) +++ Source/Entities/IEntity.cst (working copy) @@ -20,6 +20,7 @@ %> using System; using System.ComponentModel; +using System.Collections; namespace <%=NameSpace%> { @@ -140,4 +141,17 @@ /// string EntityTrackingKey { get; set; } } + + /// + /// Interface that TList and every entity implements to support + /// cloning of an object tree. + /// + public interface ICloneableEx + { + /// + /// The tracking key used to with the + /// + ///A list containing references to all objects already copied. + object Clone(IDictionary existingCopies); + } } Index: Source/Entities/ListBase.cst =================================================================== --- Source/Entities/ListBase.cst (revision 559) +++ Source/Entities/ListBase.cst (working copy) @@ -26,7 +26,7 @@ /// Supports filtering, databinding, searching and sorting. /// [Serializable] - public abstract class ListBase : BindingList, IBindingListView, IBindingList, IList, ICloneable, IListSource, ITypedList, IDisposable, IComponent, IRaiseItemChangedEvents, IDeserializationCallback + public abstract class ListBase : BindingList, IBindingListView, IBindingList, IList, ICloneable, ICloneableEx, IListSource, ITypedList, IDisposable, IComponent, IRaiseItemChangedEvents, IDeserializationCallback { private List _OriginalList = new List(); @@ -578,6 +578,15 @@ } /// + /// Creates an exact copy of this instance. + /// + /// + public virtual object Clone(IDictionary existingCopies) + { + throw new NotImplementedException("Method not implemented."); + } + + /// /// Creates an exact copy of this TList{T} object. /// ///A new, identical copy of the TList{T} casted as object. @@ -594,7 +603,31 @@ System.NotSupportedException("object not cloneable"); } } - #endregion ICloneable + + /// + /// Creates an exact copy of this TList{T} object. + /// + ///A new, identical copy of the TList{T} casted as object. + public static object MakeCopyOf(object x, IDictionary existingCopies) + { + if (x is ICloneableEx) + { + // Return a deep copy of the object + return ((ICloneableEx)x).Clone(existingCopies); + } + else if (x is ICloneable) + { + // Return a deep copy of the object + return ((ICloneable)x).Clone(); + } + else + { + throw new + System.NotSupportedException("object not cloneable"); + } + } + + #endregion ICloneable #region PropertyCollection /// Index: Source/Entities/TList.cst =================================================================== --- Source/Entities/TList.cst (revision 559) +++ Source/Entities/TList.cst (working copy) @@ -119,8 +119,18 @@ /// public override object Clone() { - return this.Copy(); + return this.Copy(null); } + + /// + /// Creates an exact copy of this TList{T} instance. + /// + ///The TList{T} object this method creates, cast as an object. + /// + public override object Clone(IDictionary existingCopies) + { + return this.Copy(existingCopies); + } /// /// Creates an exact copy of this TList{T} object. @@ -128,10 +138,26 @@ ///A new, identical copy of the TList{T}. public virtual TList Copy() { + return this.Copy(null); + } + + /// + /// Creates an exact copy of this TList{T} object. + /// + ///A new, identical copy of the TList{T}. + public virtual TList Copy(IDictionary existingCopies) + { + if (existingCopies == null) + existingCopies = new Hashtable(); + TList copy = new TList(); foreach (T item in this) { - T itemCopy = (T)MakeCopyOf(item); + T itemCopy = default(T); + if (existingCopies.Contains(item)) + itemCopy = (T)existingCopies[item]; + else + itemCopy = (T)MakeCopyOf(item, existingCopies); copy.Add(itemCopy); }