代码优先 - 当我没有将父对象设置为EntityState.Modified时,如何保存ICollection?

时间:2011-06-04 21:26:09

标签: entity-framework entity-framework-4.1 ef-code-first entity-framework-ctp5

如果我有以下课程:

public class Foo()
{
public int PropertyIWantUpdated {get; set;}
public int PropertyIDontWantUpdated (get; set}

public ICollection<Bar> Bars {get; set;}
}

保存到我的数据库时,而不是

context.Entry(thisFoo).State = EntityState.Modified;

我正在使用

context.Entry(thisFood).Property(tf => tf.PropertyIWantUpdated).IsModified = true;

我怎样才能保存对Bars的更改?

1 个答案:

答案 0 :(得分:5)

这取决于您要更新的内容。首先让我澄清一个重要的事实 - 如果你有分离的实体图(更多有关系的实体)并且你想要将所有更改传递给EF,你有责任告诉EF在每个实体和每个关系中发生了什么变化 - EF不会帮助你。

如果您尝试仅更新Bar个实例并且未更改关系(=您未向Bar添加新的Foo或从Bar移除Foo Bars)您只需要迭代Modified并将其设置为Bars州。

如果您还更改了Bar集合的内容,则整个过程变得非常复杂,方法取决于您定义实体的方式=如果您使用的是independent or foreign key association

如果是外键关联(Bar将FK作为属性=在FooId中,您有类似Bars),则遵循与开头类似的方法。您迭代Modified并将状态设置为:

    如果已将Bar分配给Foo ,则
  • Added 如果为Bar
  • 分配了新的Foo,则
  • Bar

有一个大问题。如果您从Bars集合中删除了一些Modified个实例,则还必须将它们附加到上下文并相应地设置其状态:

  • Deleted如果FK应设为null
  • Bar如果应删除Bar

这一切只适用于一对多的关系。

如果你认为以前的方法很复杂,那么在独立关联的情况下(Bar没有FK属性 - 总是多对多关系的情况),这个过程就更糟了。独立关联有自己的对象跟踪状态=设置状态DbContext实体不会保持新的关系。第一个问题是无法直接从DbContext API访问此对象 - 您必须将ObjectContext转换为ObjectStateManager并使用ObjectStateEntry来访问代表该关系的Modified。之后你必须正确设置它的状态,这不像它看起来那么容易,因为关系不能处于Unchanged状态 - 它只能在AddedDeleted或{{1} }。这意味着如果您将Bar的关系从一个更改为另一个Foo,您必须首先找到旧关系并将其设置为已删除,然后您可以将新关系设置为已添加。如果你有多对多关系并且你也想添加,删除和更新相关对象(不仅仅是关系),这可能真的“非常有趣” - 尤其是你必须在某个地方保留已经改变的信息。能够正确设置所有状态。

有关此问题的更多讨论(EF中的全局)是here - 它与DbContext API无关,但由于新API只是旧ObjectContext API的包装,因此仍存在同样的问题。

你认为这是可行的吗?我不这么认为。因此,你应该尽量避免这种情况。有一些方法可以避免它:

  • 对附加的对象图进行更改 - 这意味着您将首先将实体图的原始状态附加到上下文,然后您将进行所有更改。
  • 加载原始对象图并手动将所有更改从新图表合并到已加载(和附加)的图表。
  • 如果是ObjectContext API,您可以使用Self-tracking entities来跟踪状态并自动设置应用于上下文的所有内容。它们有一些其他disadvantages和限制(例如它们不支持延迟加载),它们不适用于DbContext API。