C# 实体框架复制对象和所有子属性
示例结构C# 实体框架复制对象和所有子属性,c#,entity-framework,C#,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
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; }
}
在上面的例子中,clonedPage
结构很好,一个新的Page
被添加到数据库中。但是我相信,因为子对象的Id是设置好的,并且子对象之间的关系总是一对多的。原始对象pageFromDb
将丢失作为实体框架的所有it子对象,而不是为克隆的页面创建新的节
对象
将更新节。PageId
到新插入的页面
我认为解决这个问题的方法是
foreach
,foreach
,等等。在插入之前,将所有Id设置为0
,然后实体框架将为每个对象创建新记录。是否有更简单/更好的方法在实体框架环境中克隆对象?为了使实体框架在持久化图时将克隆视为一个完整的新对象图,图中的所有实体都需要与检索根实体的上下文断开连接
这可以在上下文中使用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
试试这个
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;
}
publicpagecopypage(intpageid)
{
使用(上下文=新上下文())
{
context.Configuration.LazyLoadingEnabled=false;
Page dbPage=context.Pages.Where(p=>p.PageId==PageId)。包括(s=>s.Sections.Select(s=>s.Section)).First();
Page=dbPage.Clone();
page.PageId=0;
对于(int i=0;i
克隆方法的作用是什么?它在做深度复制吗?你能告诉它不要复制Id字段吗?只要你的收藏是正确的,EF将在插入后为您建立ID。@Tim仅在顶部页面对象级别使用AutoMapper。可能重复其他信息:检测到对关系“Context.Section\u Page”的角色“Section\u Page\u Target”的冲突更改。
我建议即使没有更改,也要这样做正在跟踪的导航属性仍然被填充。嗯,这很奇怪,因为页面克隆(AsNoTracking)已从上下文中完全删除,因此不能冲突。。。您是否在加载原始页面时只调用了一次上下文,如上所述?除了加载页面和保存克隆之外,还有其他针对您的上下文的工作吗?太棒了,我已经找了很多年了!这种深度克隆是C#的新特性吗?
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;
}