Question Comments
Added By:
Sigurd Decroos at:
1/8/2013 5:48:41 PM There's a little catch with this code. Primary Keys are changed, so it doesn't make a real clone, but a copy. You have to change the code a bit so the primary key gets synced too if needed.
Added By:
Mr292 at:
2/16/2013 12:45:27 PM I refactored some in order to replicate to different databases as well as to different assemblies in the other database. I came about this requirement because I wanted to remodel my DOM and did not want to have to manually do a lot of data imports.
public class CloneIXPSimpleObjectHelper
{
/// <summary>
/// A dictionary containing objects from the source session as key and objects from the
/// target session as values
/// </summary>
/// <returns></returns>
Dictionary<object, object> clonedObjects;
Session sourceSession;
UnitOfWork targetSession;
/// <summary>
/// Initializes a new instance of the CloneIXPSimpleObjectHelper class.
/// </summary>
public CloneIXPSimpleObjectHelper(Session source, UnitOfWork target)
{
clonedObjects = new Dictionary<object, object>();
sourceSession = source;
targetSession = target;
}
/// <summary>
/// Initializes a new instance of the CloneIXPSimpleObjectHelper class to Clone to Different DB.
/// </summary>
public CloneIXPSimpleObjectHelper(Session session, string connstring)
{
UnitOfWork NewUOW = new UnitOfWork(
XpoDefault.GetDataLayer(connstring, DevExpress.Xpo.DB.AutoCreateOption.SchemaAlreadyExists));
clonedObjects = new Dictionary<object, object>();
sourceSession = session;
targetSession = NewUOW;
}
/// <summary>
/// Initializes a new instance of the CloneIXPSimpleObjectHelper class to Clone to Different Assembly / DB.
/// </summary>
public CloneIXPSimpleObjectHelper(Session session, string connstring, System.Reflection.Assembly assembly)
{
var dict = new ReflectionDictionary();
foreach (var item in assembly.GetTypes())
{
if (item.IsSubclassOf(typeof(XPBaseObject)))
dict.CollectClassInfos(item);
}
UnitOfWork NewUOW = new UnitOfWork(
XpoDefault.GetDataLayer(connstring, dict,
DevExpress.Xpo.DB.AutoCreateOption.SchemaAlreadyExists));
clonedObjects = new Dictionary<object, object>();
sourceSession = session;
targetSession = NewUOW;
}
public void Commit()
{
targetSession.CommitTransaction();
}
public T Clone<T>(T source) where T : IXPSimpleObject
{
return Clone<T>(source, targetSession, CloneMethod.IgnoreIfExistsInDesitnation);
}
public T Clone<T>(T source, CloneMethod sync) where T : IXPSimpleObject
{
return (T)Clone(source as IXPSimpleObject, targetSession, sync);
}
public object Clone(IXPSimpleObject source)
{
return Clone(source, targetSession, CloneMethod.IgnoreIfExistsInDesitnation);
}
public object Clone(IXPSimpleObject source, CloneMethod sync)
{
return Clone(source as IXPSimpleObject, targetSession, sync);
}
public object Clone(IXPSimpleObject source, Session targetSession, CloneMethod sync)
{
return Clone(source as IXPSimpleObject, targetSession, sync);
}
public T Clone<T>(T source, UnitOfWork targetSession, CloneMethod sync) where T : IXPSimpleObject
{
return (T)Clone(source as IXPSimpleObject, targetSession, sync);
}
public object Clone(XPBaseObject obj, Type targetType, CloneMethod sync)
{
return Clone(obj, targetSession, targetSession.GetClassInfo(targetType), sync);
}
public enum CloneMethod
{
TransferOnly,
Synchronize,
IgnoreIfExistsInDesitnation
}
/// <summary>
/// Clones and / or synchronizes the given IXPSimpleObject.
/// </summary>
/// <param name="source"></param>
/// <param name="targetSession"></param>
/// <param name="synchronize">If set to true, reference properties are only cloned in case
/// the reference object does not exist in the targetsession. Otherwise the exising object will be
/// reused and synchronized with the source. Set this property to false when knowing at forehand
/// that the targetSession will not contain any of the objects of the source.</param>
/// <returns></returns>
public object Clone(IXPSimpleObject source, UnitOfWork parentSession, XPClassInfo cloneClassInfo, CloneMethod sync)
{
if (source == null)
return null;
object sourceKey = source.Session.GetKeyValue(source);
if (clonedObjects.ContainsKey(source))
return parentSession.GetObjectByKey(cloneClassInfo,cloneClassInfo.KeyProperty.GetValue(clonedObjects[source]));
NestedUnitOfWork nestedSession = parentSession.BeginNestedUnitOfWork();
IXPSimpleObject clone = null;
if (sync != CloneMethod.TransferOnly)
{
clone = (IXPSimpleObject)nestedSession.GetObjectByKey(cloneClassInfo, sourceKey);
if (clone != null)
{
if (sync == CloneMethod.IgnoreIfExistsInDesitnation)
{
clonedObjects.Add(source, clone);
return nestedSession.GetParentObject(clone);
}
}
}
if (clone == null)
clone = (IXPSimpleObject)cloneClassInfo.CreateNewObject(nestedSession);
clonedObjects.Add(source, clone);
try
{
XPClassInfo sourceClassInfo = source.Session.GetClassInfo(source.GetType());
if (sourceClassInfo.KeyProperty.GetType() == cloneClassInfo.KeyProperty.GetType())
cloneClassInfo.KeyProperty.SetValue(clone, sourceKey);
foreach (XPMemberInfo cloneMember in cloneClassInfo.PersistentProperties)
{
XPMemberInfo sourceMem = sourceClassInfo.GetMember(cloneMember.Name);
if (sourceMem == null
|| cloneMember is DevExpress.Xpo.Metadata.Helpers.ServiceField
|| cloneMember.IsKey)
continue;
object val = null;
if (cloneMember.ReferenceType != null)
{
object createdByClone = cloneMember.GetValue(clone);
if (createdByClone != null)
{
val = Clone((IXPSimpleObject)sourceMem.GetValue(source),
nestedSession,
nestedSession.GetClassInfo(cloneMember.MemberType),
sync==CloneMethod.TransferOnly?CloneMethod.Synchronize:sync);
}
else
if ((cloneMember.IsAggregated)
//REMOVE Below LINE IF YOU WANT TO MAINTAIN ONLY ONE WAY AGGREGATIOn
|| (cloneMember.IsAssociation
&& cloneMember.GetAssociatedMember().IsAggregated)
)
{
val = Clone((IXPSimpleObject)sourceMem.GetValue(source), nestedSession,
nestedSession.GetClassInfo(cloneMember.MemberType), sync);
}
}
else
{
val = sourceMem.GetValue(source);
}
if ((val != null) && !(val is DateTime && (DateTime)val == DateTime.MinValue))
cloneMember.SetValue(clone, val);
}
foreach (XPMemberInfo m in cloneClassInfo.CollectionProperties)
{
if (m.HasAttribute(typeof(AggregatedAttribute)))
{
XPBaseCollection col = (XPBaseCollection)m.GetValue(clone);
XPBaseCollection colSource = (XPBaseCollection)sourceClassInfo.GetMember(m.Name).GetValue(source);
foreach (IXPSimpleObject obj in new ArrayList(colSource))
{
XPClassInfo targetinfo = col.GetObjectClassInfo();
col.BaseAdd(
Clone(obj, nestedSession,
targetinfo, sync));
}
}
}
nestedSession.CommitTransaction(); //
clonedObjects[source]= clone;
return nestedSession.GetParentObject(clone);
}
catch
{
if (nestedSession.InTransaction)
nestedSession.RollbackTransaction();
}
return null;
}
}