如何深度复制实体
我在这里找到了这个片段:
public static T DeepClone(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); 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); db.Detach(myEntity); myEntity.EntityKEy = null; db.Entities.AddObject(newEntity); db.SaveChanges();
在AddObject行上获取exception:
ObjectStateManager中已存在具有相同键的对象。 ObjectStateManager无法使用相同的键跟踪多个对象。
重要的一点是,您必须在分离之前加载相关实体并创建深度克隆。 如果分离实体,则会以静默方式删除所有关系,因为Detach
方法仅适用于单个实体,而实体图形不能同时包含附加实体和分离实体。 这就是为什么你需要序列化而不是简单地调用Detach
。
不要忘记关闭延迟加载,否则您的序列化也会从数据库中提取其他导航属性的数据。 还要记住,此深层副本将在图形中创建所有实体的新版本,因此添加根实体也将添加所有相关实体。
所有子对象的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();
如果在分离实体之前尚未加载子实体,则不会序列化它们。 确保在分离实体之前加载要进行深度克隆的所有导航属性。
编辑
急切加载必须序列化的导航属性
var entity = db.Entities.Include("ChildEntity.ChildChildEntity") .Where(l=>l.ID == myId).Single();
您可能应该在尝试再次附加实体之前保存上下文
Entity newEntity = new Entity(); Eneity Entity = db.Include("ChildEntity").Where(p=>p.Id==Id).Single(); newEntity = DeepClone(Entity); db.Detach(myEntity); db.SaveChanges(); myEntity.EntityKEy = null; db.Entities.AddObject(newEntity); db.SaveChanges();