1

更新:

这让我快疯了!

经过多次谷歌搜索等。我真的离解决方案更近了......

然而,我发现了一件更让我困惑的事情——在 m_dbContext.SaveChanges() 调用之前实体的“状态”。(请参阅下面的完整存储库代码)

var updateInfoState = m_dc.Entry(oldPage.UpdateInfo).State; // State is 'Modified'
var oldPageState = m_dc.Entry(oldPage).State;               // State is 'Detached' 

this.m_dc.SaveChanges();

为什么“oldPage”是分离的?

现在好绝望!!;)

原来的:

我似乎遇到了 EF Code-First 正确更新相关表的问题。

在这个简化的示例中,“UpdateInfo”表正在使用新的 DateTime ... 进行更新,但“Pages”表并未使用新的“Name”值进行更新。

我正在通过 DropCreateDatabaseAlways / override Seed 播种代码优先 POCO ... 并且 EF 正在正确创建测试表 - 所以此时它似乎知道它在做什么......

我确信这是我想念的简单/明显的东西!

非常感谢所有帮助!

我的班级定义:

public class Page
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual UpdateInfo UpdateInfo { get; set; }  // virtual For Lazy loading
}

[Table("UpdateInfo")]                                   // much better than EF's choice of UpdateInfoes! 
public class UpdateInfo
{
    public int Id { get; set; }
    public DateTime DateUpdated { get; set; }
}

public class DomainContext : DbContext
{
    public DbSet<Page> Pages { get; set; }
    public DbSet<UpdateInfo> UpdateInfo { get; set; }
}

由 Code-First 创建的表

Pages Table
===========

    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](max) NULL,
    [UpdateInfo_Id] [int] NULL,

UpdateInfo Table
================

    [Id] [int] IDENTITY(1,1) NOT NULL,
    [DateUpdated] [datetime] NOT NULL,

我的存储库代码:

public Page Get(int id)
{
    Page page = m_dbContext.Pages.Single(p => p.Id == id);
    return page;
}

public void Update(PagePostModel model)
{
    Page oldPage = Get(model.PageModel.Id);                         // on oldPage Name = "Hello", DateUpdated = "Last Year"

    Page newPage = Mapper.Map<PageModel, Page>(model.PageModel);    // on newPage Name = "Goodbye"  (AutoMapper)
    newPage.UpdateInfo = oldPage.UpdateInfo;                        // take a copy of the old UpdateInfo since its not contained in the model

    newPage.UpdateInfo.DateUpdated = DateTime.UtcNow;               // update to now

    oldPage = newPage;                                              // copy the updated page we grabbed from dbContext above (NB Everything looks great here..oldPage is as expected)

    m_dbContext.SaveChanges();                                      // update - only the 'UpdateInfo' table is being updated - No change to 'Pages' table :(((
}
4

1 回答 1

2

如您所知,Entity Framework 中有一个更改跟踪器 api。

为了跟踪您从数据库中检索到的实体的更改,DbContext 使用它的参考值。

您上面的“更新”功能将 newPage 插入 oldPage。因此,DbContext 永远不会知道 oldPage 是 newPage。所以,它是“分离的”。

但是,对于 UpdateInfo,它是 oldPage 中引用的副本,因此 DbContext 可以跟踪它的变化。所以,它被“修改”了。

要解决这个问题,使用下面的代码怎么样?

Page newPage = Mapper.Map<PageModel, Page>(model.PageModel);
oldPage.UpdateInfo = newPage.UpdateInfo; 
oldPage.UpdateInfo.DateUpdated = DateTime.UtcNow;
m_dbContext.SaveChanges();

更新

然后,使用 Attach & Detach 方法。

这些方法可帮助您从 DbContext 附加和分离实体。

Page newPage = Mapper.Map<PageModel, Page>(model.PageModel);
// if you attach first, there will be an exception, 
// because there is two entities having same id.
m_dbContext.Entry(oldPage).State = EntityState.Detached; 
m_dbContext.Pages.Attach(newPage);
// if you don't set IsModified = true,
// DbContext cannot know it is changed.
m_dbContext.Entry(newPage).State = EntityState.Modified;
m_dbContext.SaveChanges();
于 2012-05-11T06:44:12.247 回答