Объект дублирования объекта Entity Framework и все дочерние свойства
Пример структуры
public class Page
{
public int PageId { get; set; }
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public virtual List<Section> Sections { get; set; }
}
public class Section
{
public int SectionId { get; set; }
public int PageId { get; set; }
public virtual Page Page { get; set; }
public virtual List<Heading> Headings { get; set; }
}
public class Heading
{
public int HeadingId { get; set; }
public int SectionId { get; set; }
public virtual Section Section { get; set; }
}
Стоит отметить, что моя фактическая структура имеет больше уровней, чем это, но этого должно быть достаточно, чтобы объяснить, чего я пытаюсь достичь.
Итак, я загружаю свой объект Page
, а затем клонирую этот объект и делаю небольшие изменения в свойствах Page
i.e. Prop1
, Prop2
Page pageFromDb = getPageMethod();
Page clonedPage = pageFromDb.Clone();
clonedPage.Prop1 = clonedPage.Prop1 + " Cloned";
addPageMethod(clonedPage); //Adds the page to db
В приведенном выше примере clonedPage
структура прекрасна, и в базу данных добавляется новый Page
. Однако я верю, потому что Идентификатор дочерних объектов задан, и отношение детей всегда одно для многих. Исходный объект pageFromDb
потеряет все дочерние элементы в качестве рамки сущности вместо создания новых объектов Section
для клонированного Page
обновит Section.PageId
на вновь вставленной странице.
Я считаю, что исправление для этого было бы foreach
, foreach
и т.д. и установить все идентификаторы на 0
перед вставкой, тогда инфраструктура сущности создаст новые записи для каждого объекта. Есть ли более простой/лучший способ клонирования объекта в среде фреймворка сущности.?
Ответы
Ответ 1
Для того, чтобы Entity Framework обрабатывала клон как целый новый граф объектов при сохранении графика, все сущности в графе должны быть отключены из контекста, в котором был восстановлен корневой объект.
Это можно сделать с помощью метода AsNoTracking
в контексте.
Например, это приведет к отображению графика страницы и связанных разделов из базы данных и отключению отслеживания. Эффективно это клон, как если бы вы добавили его в свой DbSet страницы и сохранили его, создаст совершенно новый граф объектов в базе данных. То есть новый объект страницы и новые подразделения Секции. Обратите внимание: вам не нужно вызывать ваш метод Clone
.
var clone = context.Pages
.AsNoTracking()
.Including(pages => pages.Sections)
.Single(...);
context.Pages.Add(clone);
context.SaveChanges(); // creates an entirely new object graph in the database
Ответ 2
Попробуйте это!
public Page CopyPage(int pageID)
{
using(Context context = new Context())
{
context.Configuration.LazyLoadingEnabled = false;
Page dbPage = context.Pages.Where(p => p.PageId == pageID).Include(s => s.Sections.Select(s => s.Section)).First();
Page page = dbPage.Clone();
page.PageId = 0;
for (int i = 0; i < dbPage .Sections.Count; i++)
page.Sections[i] = new Section
{
SectionId = 0,
PageId = 0,
Page = null,
Headings = dbPage[i].Headings
};
return page;
}
}
public Page Clone()
{
Object page = this.GetType().InvokeMember("", BindingFlags.CreateInstance, null, this, null);
foreach(PropertyInfo propertyInfo in this.GetType().GetProperties())
{
if(propertyInfo.CanWrite)
{
propertyInfo.SetValue(page, propertyInfo.GetValue(this, null), null);
}
}
return page;
}