【问题标题】:Entity Framework duplicate object and all child properties实体框架重复对象和所有子属性
【发布时间】:2014-09-09 18:51:12
【问题描述】:

示例结构

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 将失去它作为实体框架的所有子对象,而不是为克隆的Page 创建新的Section 对象会将Section.PageId 更新为新插入的页面。

我相信解决此问题的方法是 foreachforeach 等,并在插入之前将所有 Id 设置为 0,然后实体框架将为每个对象创建新记录。有没有更简单/更好的方法可以在实体框架环境中克隆对象?

【问题讨论】:

  • 克隆方法有什么作用?是在做深拷贝吗?你能告诉它不要复制 ID 字段吗?只要您的集合是正确的,EF 就会在插入后为您建立 Id。
  • @Tim 只是在 Page 对象级别的顶部使用 AutoMapper。

标签: c# entity-framework


【解决方案1】:

为了让实体框架在持久化图表时将克隆视为一个全新的对象图表,图表中的所有实体都需要与检索根实体的上下文断开

这可以在上下文中使用AsNoTracking 方法来完成。

例如,这将从数据库中提取页面和关联的部分图表并关闭跟踪。实际上,这是一个克隆,就像您将其添加到您的 Page DbSet 并保存它一样,它将在数据库中创建一个全新的对象图。 IE。一个新的 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

【讨论】:

  • Additional information: Conflicting changes to the role 'Section_Page_Target' of the relationship 'Context.Section_Page' have been detected. 我建议即使没有跟踪更改,导航属性仍然​​会被填充。
  • 嗯,这很奇怪,因为页面克隆 (AsNoTracking) 已完全从上下文中删除,因此不会发生冲突...您是否如上所述通过对上下文的一次调用来加载原始页面?除了加载页面和保存克隆之外,还有其他针对您的上下文的工作吗?
  • 伟大的帖子 - 我多年来一直在寻找这个!这种深度克隆是 C# 的新特性吗?
【解决方案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;   
    }

【讨论】:

    猜你喜欢
    • 2012-02-23
    • 1970-01-01
    • 2012-04-25
    • 1970-01-01
    • 1970-01-01
    • 2011-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多