using DevExpress.Xpo; using DevExpress.Xpo.Metadata; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Ips.Library.DxpLib { public class CloneHelper : IDisposable { readonly Dictionary clonedObjects; readonly Session targetSession; public CloneHelper(Session targetSession) { clonedObjects = new Dictionary(); this.targetSession = targetSession; } public T Clone(T source) { return Clone(source, false); } public T Clone(T source, bool synchronize) { return (T)Clone((object)source, synchronize); } public object Clone(object source) { return Clone(source, false); } public object Clone(object source, bool synchronize) { if (source == null) return null; XPClassInfo targetClassInfo = targetSession.GetClassInfo(source.GetType()); object target = targetClassInfo.CreateNewObject(targetSession); clonedObjects.Add(source, target); foreach (XPMemberInfo m in targetClassInfo.PersistentProperties) { CloneProperty(m, source, target, synchronize); } foreach (XPMemberInfo m in targetClassInfo.CollectionProperties) { CloneCollection(m, source, target, synchronize); } return target; } private void CloneProperty(XPMemberInfo memberInfo, object source, object target, bool synchronize) { if (memberInfo is DevExpress.Xpo.Metadata.Helpers.ServiceField || memberInfo.IsKey) { return; } object clonedValue = null; if (memberInfo.ReferenceType != null) { object value = memberInfo.GetValue(source); if (value != null) { clonedValue = CloneValue(value, synchronize, false); } } else { clonedValue = memberInfo.GetValue(source); } memberInfo.SetValue(target, clonedValue); } private void CloneCollection(XPMemberInfo memberInfo, object source, object target, bool synchronize) { if (memberInfo.IsAssociation && (memberInfo.IsManyToMany || memberInfo.IsAggregated)) { XPBaseCollection colTarget = (XPBaseCollection)memberInfo.GetValue(target); XPBaseCollection colSource = (XPBaseCollection)memberInfo.GetValue(source); foreach (IXPSimpleObject obj in colSource) { colTarget.BaseAdd(CloneValue(obj, synchronize, !memberInfo.IsManyToMany)); } } } private object CloneValue(object propertyValue, bool synchronize, bool cloneAlways) { if (clonedObjects.ContainsKey(propertyValue)) { return clonedObjects[propertyValue]; } object clonedValue = null; if (synchronize && !cloneAlways) { clonedValue = targetSession.GetObjectByKey(targetSession.GetClassInfo(propertyValue), targetSession.GetKeyValue(propertyValue)); } if (clonedValue == null) { clonedValue = Clone(propertyValue, synchronize); } return clonedValue; } public void Dispose() { if (targetSession != null) targetSession.Dispose(); } } }