Как глубоко копировать сущность - PullRequest
11 голосов
/ 26 января 2012

Я нашел этот фрагмент здесь :

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 не может отслеживать несколько объектов с одним и тем же ключом.

Ответы [ 4 ]

7 голосов
/ 26 января 2012

Важным моментом является то, что вы должны загрузить связанные сущности и создать глубокий клон до отсоединения . Если вы отсоединяете сущность, все отношения удаляются без вывода сообщений, потому что метод Detach работает только для одной сущности, а граф сущностей не может состоять как из присоединенных, так и отсоединенных сущностей. По этой причине вам нужна сериализация вместо простого вызова Detach.

Не забудьте отключить отложенную загрузку, иначе ваша сериализация также будет извлекать данные для других навигационных свойств из базы данных. Также помните, что эта глубокая копия создаст новую версию всех объектов на графике, поэтому добавление корневого объекта также добавит все связанные объекты.

5 голосов
/ 03 февраля 2012

EntityKeys для всех дочерних объектов также клонируется, поэтому вам нужно установить нулевой EntityKey каждого дочернего объекта перед попыткой добавить их с помощью AddObject.

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();
4 голосов
/ 26 января 2012

Если вы не загрузили дочерние объекты до отсоединения, они не будут сериализованы. Убедитесь, что все навигационные свойства, которые вы хотите глубоко клонировать, загружены, прежде чем отсоединять объект.

Редактировать

Стремится загрузить навигационные свойства, которые должны быть сериализованы

var entity = db.Entities.Include("ChildEntity.ChildChildEntity")
        .Where(l=>l.ID == myId).Single();
2 голосов
/ 01 февраля 2012

Возможно, вам следует сохранить контекст, прежде чем пытаться присоединить объект еще раз

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();  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...