Asp.net mvc 如何优雅地重新连接EntityFramework5POCO结构并保存它?

Asp.net mvc 如何优雅地重新连接EntityFramework5POCO结构并保存它?,asp.net-mvc,entity-framework,poco,entity-framework-5,Asp.net Mvc,Entity Framework,Poco,Entity Framework 5,我正在使用EntityFramework5(首先是数据库和生成的POCO)制作一个MVC4 web应用程序,用于数据访问 在应用程序中,用户通过几个屏幕创建或编辑文档(称为“案例研究”)。当他们到达最终屏幕时,他们的文档作为案例研究POCO存在于内存中,在将此结构保存到数据库之前,一切都很好 为了存储文档,我定义了几个数据库表,这些表依次映射到业务层使用的EF POCO,然后由MVC控制器使用。因此,短期DBContext用于检索POCO并将其存储在请求之间的会话中 因此,“保存”屏幕必须将此P

我正在使用EntityFramework5(首先是数据库和生成的POCO)制作一个MVC4 web应用程序,用于数据访问

在应用程序中,用户通过几个屏幕创建或编辑文档(称为“案例研究”)。当他们到达最终屏幕时,他们的文档作为案例研究POCO存在于内存中,在将此结构保存到数据库之前,一切都很好

为了存储文档,我定义了几个数据库表,这些表依次映射到业务层使用的EF POCO,然后由MVC控制器使用。因此,短期DBContext用于检索POCO并将其存储在请求之间的会话中

因此,“保存”屏幕必须将此POCO的内容保存到现有表数据(类别、布局和节表)以及添加或更新的数据(CaseStudySections和CaseStudio本身)的导航属性中。因此,所有POCO要么都是新的,要么用于检索它们的上下文早已被弃置。换句话说,他们都是“超脱的”

这篇文章的不同寻常之处在于,我已经有了一个可行的解决方案。问题在于它体积庞大、易碎且不美观。我把代码贴在下面。请注意,通过子集合的迭代、显式添加和附加、必须获取条目对象并将单个属性标记为已修改,以便更新它们,以及最后的糟糕歌舞以同步AdditionalMaterials集合。如果这是处理EF5中分离的POCO所需要的,我将感到失望

我是不是遗漏了什么?这是否符合最佳实践?是否有更优雅和/或简洁的方式来附加POCO结构和插入/更新

保存案例研究的代码:

public void SaveCaseStudy(CaseStudy caseStudy)
{
    foreach (var s in caseStudy.CaseStudySections)
    {
        this.Entities.Sections.Attach(s.Section);

        if (s.CreatedByRefId == default(Guid))
        {
            s.CreatedByRefId = this.UserRefId;
            s.CreatedTime = DateTime.Now;
            this.Entities.CaseStudySections.Add(s);
        }
        else
        {
            this.Entities.CaseStudySections.Attach(s);
            var entry = this.Entities.Entry(s);
            entry.Property(e => e.TextData).IsModified = true;
            entry.Property(e => e.BinaryData).IsModified = true;
        }

        s.LastModifiedByRefId = this.UserRefId;
        s.LastModifiedTime = DateTime.Now;
    }

    foreach (var m in caseStudy.AdditionalMaterials)
    {
        if (m.CreatedByRefId == default(Guid))
        {
            m.CreatedByRefId = this.UserRefId;
            m.CreatedTime = DateTime.Now;
            this.Entities.AdditionalMaterials.Add(m);
        }
        else
        {
            this.Entities.AdditionalMaterials.Attach(m);
        }

        m.LastModifiedByRefId = this.UserRefId;
        m.LastModifiedByTime = DateTime.Now;
    }

    this.Entities.Layouts.Attach(caseStudy.Layout);
    this.Entities.Categories.Attach(caseStudy.Category);

    if (caseStudy.CreatedByRefId != default(Guid))
    {
        this.Entities.CaseStudies.Attach(caseStudy);
        var entry = this.Entities.Entry(caseStudy);
        entry.Property(e => e.CaseStudyName).IsModified = true;
        entry.Property(e => e.CaseStudyTitle).IsModified = true;
    }
    else
    {
        this.Entities.CaseStudies.Add(caseStudy);
        caseStudy.CreatedByRefId = this.UserRefId;
        caseStudy.CreatedTime = DateTime.Now;
    }

    caseStudy.LastModifiedByRefId = this.UserRefId;
    caseStudy.LastModifiedTime = DateTime.Now;

    if (caseStudy.CaseStudyStatus != (int)CaseStudyStatus.Personalized)
    {
        caseStudy.CaseStudyStatus = (int)CaseStudyStatus.PendingApproval;
    }

    caseStudy.ApprovedByRefId = null;
    caseStudy.ApprovedTime = null;
    this.Entities.SaveChanges();

    var existingAdditionalMaterialRefIds = caseStudy.AdditionalMaterials
        .Select(m => m.AdditionalMaterialRefId)
        .ToArray();

    var additionalMaterialsToRemove = this.Entities.AdditionalMaterials
        .Where(m => 
            m.CaseStudyRefId == caseStudy.CaseStudyRefId && 
            !existingAdditionalMaterialRefIds.Contains(m.AdditionalMaterialRefId))
        .ToArray();

    foreach (var additionalMaterialToRemove in additionalMaterialsToRemove)
    {
        this.Entities.AdditionalMaterials.Remove(additionalMaterialToRemove);
    }

    this.Entities.SaveChanges();
}

一般来说,这是你必须做的。附加分离的对象图形时,必须将要执行的每个更改告知EF。我并不是说你的代码不能简化,但如果你想添加或修改它,你仍然需要处理每个实体并设置它的状态

虽然有点老,但仍然是关于这个主题的有效答案——简言之,自从我编写它以来,没有任何变化,只创建了新的DbContext API,它仍然位于旧API之上。到目前为止,我所看到的关于这个主题的最好描述是在这本书中。

如何做:

db.CaseStudies.Attach(caseStudy);
db.Entry(caseStudy).State = EntityState.Modified;
db.SaveChange();

这将把模型中的所有更改保存到数据库中。

不幸的是,这不起作用。在我们的例子中,它产生了一个DbUpdateConcurrencyException:
Store update、insert或delete语句,它影响了意外的行数(0)。自加载实体后,实体可能已被修改或删除。刷新ObjectStateManager条目。
。这可能是因为案例研究包含一些数据对象,其中一些已经存在于数据库中(因此显然需要显式重新连接),而另一些是新的,需要插入。