Как глубоко копировать объект

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

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();

IT работает, но не копирует любые вложенные\связанные записи. что я делаю неправильно здесь?

У меня есть эта структура Entity- > ChildEntity → ChildChildEntity
- > - один-ко-многим
поэтому я предполагаю, что когда я копирую объект, он также скопирует все дочерние записи.

UPDATE: После предложений я сделал следующее:

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

Ответ 1

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

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

Ответ 2

EntityKeys для всех дочерних объектов также клонируются, поэтому вам необходимо установить каждый дочерний EntityKey в значение null, прежде чем пытаться добавить их с помощью 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();

Ответ 3

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

Edit

Ожидающая загрузка навигационных свойств, которые должны быть сериализованы

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

Ответ 4

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

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();