2012-03-14 44 views
3

的子类的浅拷贝/克隆我们已经在我们的数据库审计表,并在更新旧的和新的值序列化为XML并存储在同一排。对象是目前深克隆这样的:创建EntityObject

public EntityObject CloneEntity(EntityObject obj) 
{ 
    DataContractSerializer dcSer = new DataContractSerializer(obj.GetType()); 

    MemoryStream memoryStream = new MemoryStream(); 

    dcSer.WriteObject(memoryStream, obj); 

    memoryStream.Position = 0; 

    EntityObject newObject = (EntityObject)dcSer.ReadObject(memoryStream); 

    return newObject; 
} 

虽然这个工作,它是由于相关记录生成大量数据从深克隆拉,与成千上万的读取从DB上dcSer.WriteObject(memoryStream, obj) ,最终的MemoryStream大小约为200MB,更不用说写回数据库的数据量。不理想。

所以我想这样做一个按成员的克隆,而不是,因为这是我的理解是一个按成员克隆将离开对象引用出来,避免将所有相关的实体框架模型。

所以我这样做:

public EntityObject CloneEntity(EntityObject obj) 
{ 
    EntityObjectAuditable auditable = (EntityObjectAuditable)obj; // invalid cast exception 

    return auditable.ShallowCopy(); 
} 

// .... 

public class EntityObjectAuditable : EntityObject 
{ 
    public EntityObjectAuditable ShallowCopy() 
    { 
     return (EntityObjectAuditable)this.MemberwiseClone(); 
    } 
} 

,但我得到一个无效转换异常,因为输入EntityObject的实际类型是与表本身的子类。

我也使用扩展方法来访问MemberwiseClone()尝试过,但扩展方法无法访问受保护的方法。

所以,我怎样才能创建一个通用EntityObject的浅表副本?

+0

我看到有人问前一段时间,但是我有完全相同的问题,并因此增加了,作为一个解决方案出来了回答任何人想知道! – markmnl 2012-10-11 00:24:55

回答

3

我的第一个建议是试试这个,这类似于你现在在做什么,但很适合我用很少的开销:

DataContractSerializationUtils.SerializeToXmlString(Entity, throwExceptions); 

另外,我用这个方法之前,成功,并没有发现输出太冗长。这似乎与你现在正在做的事情几乎完全相同。

/// <summary> 
    /// Creates an exact duplicate of the entity provided 
    /// </summary> 
    /// <param name="source">The source copy of the entity</param> 
    /// <returns>An exact duplicate entity</returns> 
    public TEntity Clone(TEntity Source) 
    { 
     // Don’t serialize a null object, simply return the default for that object 
     if (ReferenceEquals(Source, null)) 
     { 
      return default(TEntity); 
     } 
     var dcs = new DataContractSerializer(typeof (TEntity)); 
     using (Stream stream = new MemoryStream()) 
     { 
      dcs.WriteObject(stream, Source); 
      stream.Seek(0, SeekOrigin.Begin); 
      return (TEntity) dcs.ReadObject(stream); 
     } 
    } 

如果这两个选项看起来很有吸引力,我的建议是写一个使用反射来的任何属性从源实体复制一个简短的函数。

+0

感谢您的回复。 'DataContractSerializationUtils.SerializeToXmlString'似乎来自西风网络工具包,我不想将其包含在我的控制台应用程序中;第二种方法遇到与我目前所做的完全相同的问题;和第三? Urgh。反射。创建一个浅层克隆真的不应该是这么艰难和脆弱,特别是考虑到'MemberwiseClone'存在。 – sennett 2012-03-14 03:52:59

+0

Blimey我刚刚阅读我的评论,我碰到了一个冲洗!对于那个很抱歉。非常感谢您的帮助。我最终使用反射,这个答案帮助我从一个类型实例化一个新的实例:http://stackoverflow.com/questions/752/get-a-new-object-instance-from-a-type-in​​- c-sharp – sennett 2012-03-14 04:11:38

+0

我同意它不应该那么难。乐意效劳! – msigman 2012-03-14 11:11:46

2

来自:

http://www.codeproject.com/Tips/474296/Clone-an-Entity-in-Entity-Framework-4

它更efficant和更快然后系列化 - 正是你要找的!基本上它使用反射来将需要的属性复制到相同类型的新EntityObject,并且能够通过使用泛型从任何派生自EntityObject的类执行此操作。

public static T CopyEntity<T>(MyContext ctx, T entity, bool copyKeys = false) where T : EntityObject 
{ 
T clone = ctx.CreateObject<T>(); 
PropertyInfo[] pis = entity.GetType().GetProperties(); 

foreach (PropertyInfo pi in pis) 
{ 
    EdmScalarPropertyAttribute[] attrs = (EdmScalarPropertyAttribute[])pi.GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false); 

    foreach (EdmScalarPropertyAttribute attr in attrs) 
    { 
     if (!copyKeys && attr.EntityKeyProperty) 
      continue; 

     pi.SetValue(clone, pi.GetValue(entity, null), null); 
    } 
} 

return clone; 
} 

例如说你有一个实体:客户,其中有导航属性:订单。然后,您可以使用复制的客户和他们的订单上面的方法,像这样:

Customer newCustomer = CopyEntity(myObjectContext, myCustomer, false); 

foreach(Order order in myCustomer.Orders) 
{ 
    Order newOrder = CopyEntity(myObjectContext, order, true); 
    newCustomer.Orders.Add(newOrder); 
}