实体框架重复对象和所有子属性

时间:2014-07-18 15:08:39

标签: 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 { 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的属性进行了一些细微的更改,即Prop1Prop2

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更新为新插入的页面。

我相信对此的修复将是foreachforeach等,并在插入之前将所有Id设置为0然后实体框架将创建foreach对象的新记录。是否有更简单/更好的方法来克隆实体框架环境中的对象。?

2 个答案:

答案 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;   
    }