Как скопировать объект из одного контекста (наследующего от DbContext
) на другой?
Все, что я нашел, работает только для ObjectContext
, но не для DbContext
или использует DbContext
, но не работает.
Например, я нашел/попробовал:
- Использует ObjectContext: CloneHelper в CodeProject
- Настройка LazyLoadingEnabled на false приводит к не заполнению свойств ICollection < > (внешних ключей)
- Настройка ProxyCreationEnabled на false приводит к сохранению свойств ICollection < > как нулевых (внешних ключей)
- Entry < > State = Отдельные результаты не заполняют свойства ICollection < > (внешние ключи), если они установлены перед добавлением свойства, или блокируют очистку идентификатора, если он установлен позже.
- AsNoTracking() приводит к исключению (одно из следующего: зависит от того, вставляет ли сначала удаленный контекст элемент из родительского свойства ICollection < > или сначала родителя):
- Родитель: объект в роли "ModelFirstSub_First_Target" не может быть автоматически добавлен в контекст, потому что он был извлечен с помощью параметра слияния NoTracking. Явно привязываю объект к объекту ObjectContext перед определением отношения.
- Элемент: объект не может быть добавлен или присоединен, поскольку его EntityReference имеет значение свойства EntityKey, которое не соответствует EntityKey для этого объекта.
Я буду использовать его для двух целей:
- Скопировать все из одной базы данных в другую (целевой будет клонировать оригинал, локальную копию удаленной базы данных). Идентификаторы объектов должны быть сохранены.
- Добавить или обновить выбранные объекты из одной базы данных в другую (восходящие изменения в локальном кэше удаленного источника). Идентификаторы вновь созданных объектов не должны сохраняться.
Как это сделать?
EF 6.1.1,.NET 4.5.2, С#
Вот тестовый код, который пытается имитировать второе действие (восходящее изменение возвращается к удаленной базе данных):
var addedFirst = localContext.Firsts.AsNoTracking().Single(m => m.Id == 4);
var updatedFirst = localContext.Firsts.AsNoTracking().Single(m => m.Id == 2);
addedFirst.Items.First().Id = 0;
addedFirst.Items.First().FirstId = 0;
addedFirst.Id = 0;
remoteContext.FirstItems.Add(addedFirst.Items.First());
remoteContext.Firsts.Add(addedFirst);
var originalFirst = remoteContext.Firsts.Single(m => m.Id == 2);
var originalItem = originalFirst.Items.First();
originalItem.Title = updatedFirst.Items.First().Title;
Вот модель:
public class ModelFirstBase
{
public virtual int Id { get; set; }
public virtual ICollection<ModelFirstSub> Items { get; set; }
public virtual string Title { get; set; }
}
public class ModelFirstSub
{
public virtual int Id { get; set; }
public virtual int FirstId { get; set; }
public virtual ModelFirstBase First { get; set; }
public virtual string Title { get; set; }
}
PS: свойства должны поддерживаться виртуальными, поскольку модель разделяется с производственным приложением, которое использует динамические прокси.