实体框架 - 为什么要明确地将实体状态设置为已修改?

时间:2011-08-18 10:51:04

标签: entity-framework

官方文档说修改实体我检索DbEntityEntry对象并使用属性函数或我将其状态设置为修改。它使用以下示例

Department dpt = context.Departments.FirstOrDefault();
DbEntityEntry entry = context.Entry(dpt);
entry.State = EntityState.Modified;

我不理解第二和第三声明的目的。如果我向框架询问第一个语句之类的实体,然后按照

修改POCO
dpt.Name = "Blah"

如果我再向EF询问SaveChanges(),则实体的状态为状态(我通过快照跟踪进行猜测,这不是代理)并且更改是持久化而无需手动设置状态。我在这里错过了什么吗?

2 个答案:

答案 0 :(得分:44)

在您的方案中,您确实无需设置状态。更改跟踪的目的是找到您已更改附加实体的值并将其置于修改状态。在分离的实体(加载的实体没有更改跟踪或在当前上下文之外创建)的情况下,手动设置状态非常重要。

答案 1 :(得分:21)

如上所述,在具有断开连接的实体的场景中,将实体的状态设置为Modified会很有用。如果您只是附加断开连接的实体,而不是从数据库中提取实体并修改并保存它,它会将数据包保存到数据库。

但是有一个很好的理由不把状态设置为Modified(我确定Ladislav意识到这一点,但我仍然想在这里指出它们)。

  1. 记录中的所有字段都将更新,而不仅仅是更改。有许多系统可以审核更新。更新所有字段会导致大量混乱或需要审核机制来过滤掉错误的更改。

  2. 乐观并发。由于所有字段都已更新,因此可能会导致更多冲突。如果两个用户同时更新相同的记录但不是相同的字段,则不需要发生冲突。但如果它们始终更新所有字段,则最后一个用户将始终尝试写入陈旧数据。这最多会导致乐观的并发异常,或者在最坏的情况下导致数据丢失。

  3. 无用的更新。无论如何,该实体都被标记为已修改。未更改的实体也将触发更新。如果可以打开编辑窗口以查看详细信息并由OK关闭,则可能很容易发生这种情况。

  4. 所以这是一个很好的平衡。减少往返或减少冗余。

    无论如何,将状态设置为Modified的替代方法是(使用DbContext API):

    void UpdateDepartment(Department department)
    {
        var dpt = context.Departments.Find(department.Id);
        context.Entry(dpt).CurrentValues.SetValues(department);
        context.SaveChanges();
    }
    

    CurrentValues.SetValues将各个属性标记为Modified

    或者附加断开连接的实体并手动将单个属性标记为Modified

    context.Entry(dpt).State = System.Data.Entity.EntityState.Unchanged;
    context.Entry(dpt).Property(d => d.Name).IsModified = true;