|
public static void DeepClone(Entity objectToClone, JTS2Entities mgr, Action<Entity> callBack) { Dictionary<EntityKey, Entity> clonedItems = new Dictionary<EntityKey, Entity>(); DeepClone( objectToClone, mgr, clonedItems, callBack); } private static void DeepClone(Entity objectToClone, JTS2Entities mgr, Dictionary<EntityKey, Entity> clonedItems, Action<Entity> callBack) { ((IMyCloningMethods) objectToClone).GetEntityGraphAsync((list) => { //set up clones foreach (Entity relatedItem in list) { Entity relatedClone=(Entity) ((ICloneable) relatedItem).Clone(); MakeUnique((IMyCloningMethods) relatedClone); mgr.AddEntity(relatedClone); clonedItems.Add(relatedItem.EntityAspect.EntityKey, relatedClone); } //fix up IDs foreach (Entity relatedItem in list) { FixForeignKeys(clonedItems[relatedItem.EntityAspect.EntityKey], clonedItems); } foreach (Entity relatedItem in list) { RelinkRelations(relatedItem, clonedItems[relatedItem.EntityAspect.EntityKey], clonedItems); } callBack(clonedItems[objectToClone.EntityAspect.EntityKey]); }); } private static void FixForeignKeys(Entity clone, Dictionary<EntityKey, Entity> clonedItems) { var props = clone.GetType().GetProperties(); foreach (var prop in props) { var attr = prop.GetCustomAttributes(typeof(RelationPropertyAttribute), true); if (attr.Length > 0) { if (((RelationPropertyAttribute)attr[0]).QueryDirection == QueryDirection.ToRole2) { if (!IsSubclassOfRawGeneric(typeof(RelatedEntityList<>), prop.PropertyType)) { EntityKey key = ((Entity)prop.GetGetMethod().Invoke(clone, null)).EntityAspect.EntityKey; if (clonedItems.ContainsKey(key)) { var newRelatedItem = clonedItems[key]; prop.GetSetMethod().Invoke(clone, new object[] { newRelatedItem }); } } } } } }
private static void RelinkRelations(Entity objectToClone, Entity clone, Dictionary<EntityKey, Entity> clonedItems) { var props = objectToClone.GetType().GetProperties(); foreach (var prop in props) { if (IsSubclassOfRawGeneric(typeof(RelatedEntityList<>), prop.PropertyType)) { IList listToClone = (IList)prop.GetGetMethod().Invoke(objectToClone, null); IList listOfClone = (IList)prop.GetGetMethod().Invoke(clone, null); listOfClone.Clear(); if (listToClone != null) { //Need an umboundList because the list could be updated by the addition of new clones e.g. in many to many relationships List<Entity> unboundListToClone = new List<Entity>(); foreach (var listItem in listToClone) {
if (listItem is Entity) { unboundListToClone.Add((Entity)listItem); } } foreach (var listItem in unboundListToClone) { Entity relatedObject; if (clonedItems.ContainsKey(listItem.EntityAspect.EntityKey)) { relatedObject = clonedItems[listItem.EntityAspect.EntityKey]; } else { relatedObject = listItem; } listOfClone.Add(relatedObject); } } } } } static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) { while (toCheck != typeof(object)) { var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck; if (generic == cur) { return true; } toCheck = toCheck.BaseType; } return false; } static private void MakeUnique(IMyCloningMethods entity) { foreach (var propName in entity.FieldsWithUniqueConstraint) //this is a list of field names (string) that I maintain manually in code { var prop = entity.GetType().GetProperty(propName); //make name unique then set it back to the property object[] parameters = {prop.GetGetMethod().Invoke(entity, null) + " copied on " + DateTime.Now.ToString("dd-MMM-yyyy hh:mm:ss")}; prop.GetSetMethod().Invoke(entity, parameters); } }
|