【问题标题】:How to deep copy an entity如何深拷贝实体
【发布时间】:2012-02-19 06:19:25
【问题描述】:

我找到了这个sn-p here

public static T DeepClone<T>(this T obj)
    {
        using (var ms = new MemoryStream()) {
            var bf = new BinaryFormatter();
            bf.Serialize(ms, obj);
            ms.Position = 0;
            return (T)bf.Deserialize(ms);
        }
    }

里面说我们可以通过这个东西做所有相关对象的深拷贝。

我正在尝试像这样复制:

db.Detach(myEntity); 
myEntity.EntityKEy = null;
Entity newEntity = new Entity();
newEntity = DeepClone<Entity>(Entity);
db.Entities.AddObject(newEntity);
db.SaveChanges();

它可以工作,但仍然没有复制任何嵌套\相关的记录。我在这里做错了什么?

我有这个结构 Entity->ChildEntity ->ChildChildEntity
-> - 一对多
所以我假设当我复制实体时它也会复制所有子记录。

更新: 根据建议,我这样做了:

Entity newEntity = new Entity();
Eneity Entity = db.Include("ChildEntity").Where(p=>p.Id==Id).Single();
newEntity = DeepClone<Entity>(Entity);
db.Detach(myEntity); 
myEntity.EntityKEy = null;
db.Entities.AddObject(newEntity);
db.SaveChanges();

在 AddObject 行获取异常:

ObjectStateManager 中已存在具有相同键的对象。 ObjectStateManager 无法跟踪具有相同的多个对象 键。

【问题讨论】:

  • 您确定它们在原始对象中不为空吗?
  • @JamesD'Angelo,是的,你是对的,如果查看调试,参考表是空的:(。为什么会发生这种情况?这就是我检索原始对象的方式:Entity original = db。 Entities.Where(l=>l.ID == myId).Single();
  • 您可以发布您实体的代码吗?
  • 这是一种令人讨厌的深度复制方式...不是很高效...
  • @FelixK.,有什么好办法?

标签: c# entity-framework .net-4.0


【解决方案1】:

如果您在分离实体之前没有加载子实体,它们将不会被序列化。确保在分离实体之前加载所有要深度克隆的导航属性。

编辑

急切加载必须序列化的导航属性

var entity = db.Entities.Include("ChildEntity.ChildChildEntity")
        .Where(l=>l.ID == myId).Single();

【讨论】:

  • 我认为这正是发生的事情。有什么简单的方法可以加载孩子吗?
  • @user194076 更新了我的答案
【解决方案2】:

重要的一点是您必须加载相关实体并创建深度克隆在分离之前。如果您分离实体,所有关系都会被静默删除,因为Detach 方法仅适用于单个实体,并且实体图不能同时包含附加实体和分离实体。这就是为什么您需要序列化而不是简单地调用 Detach 的原因。

不要忘记关闭延迟加载,否则您的序列化也会从数据库中提取其他导航属性的数据。另请记住,此深层副本将创建图中所有实体的新版本,因此添加根实体也会添加所有相关实体。

【讨论】:

    【解决方案3】:

    您可能应该在尝试再次附加实体之前保存上下文

    Entity newEntity = new Entity();   
    Eneity Entity = db.Include("ChildEntity").Where(p=>p.Id==Id).Single();   
    newEntity = DeepClone<Entity>(Entity);   
    db.Detach(myEntity);    
    db.SaveChanges();  
    myEntity.EntityKEy = null;   
    db.Entities.AddObject(newEntity);   
    db.SaveChanges();  
    

    【讨论】:

    【解决方案4】:

    所有子对象的 EntityKeys 也会被克隆,因此在尝试使用 AddObject 添加它们之前,您需要将每个子对象的 EntityKey 设置为 null。

    Entity oldEntity = db.Include("ChildEntity").Where(p => p.Id == Id).Single();
    Entity newEntity = oldEntity.DeepClone(); // assuming you've put your DeepClone extension method in a static class so that it can be used as an extension
    newEntity.EntityKey = null;
    foreach(var childEntity in newEntity.ChildEntities)
    {
        childEntity.EntityKey = null;
    }
    db.Entities.AddObject(newEntity);
    db.SaveChanges();
    

    【讨论】:

    • 使用这种方法,您甚至不需要 DeepClone。只需从 Db 加载实体并清除所有主键。当然这可能只适用于 ef-codefirst
    猜你喜欢
    • 1970-01-01
    • 2010-11-30
    • 2012-04-12
    • 1970-01-01
    • 2015-01-13
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多