示例结构
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
的属性进行了一些细微的更改,即Prop1
,Prop2
Page pageFromDb = getPageMethod();
Page clonedPage = pageFromDb.Clone();
clonedPage.Prop1 = clonedPage.Prop1 + " Cloned";
addPageMethod(clonedPage); //Adds the page to db
在上面的示例中,clonedPage
结构很好,并且新的Page
被添加到数据库中。但是我相信因为孩子们的Id对象被设定了,孩子们的关系总是一对多。原始对象pageFromDb
将丢失所有子项作为实体框架,而不是为克隆的Section
创建新的Page
对象,将Section.PageId
更新为新插入的页面。
我相信对此的修复将是foreach
,foreach
等,并在插入之前将所有Id设置为0
然后实体框架将创建foreach对象的新记录。是否有更简单/更好的方法来克隆实体框架环境中的对象。?
答案 0 :(得分:31)
为了让实体框架在持久化图形时将克隆视为一个完整的新对象图形,图形中的所有实体都需要与检索根实体的上下文断开连接。
可以使用上下文中的AsNoTracking
方法完成此操作。
例如,这将从数据库中提取页面和关联的部分图形并关闭跟踪。实际上,这是一个克隆,就好像你将它添加到你的Page DbSet并保存它将在数据库中创建一个全新的对象图。即相应地,新的Page实体和新的Section实体。请注意,您无需调用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
答案 1 :(得分:1)
试试这个!
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;
}