代码第一 - 当我没有将父对象设置为EntityState.Modified时,如何保存ICollection? [英] Code first - how can I save an ICollection when I'm not setting the parent object to EntityState.Modified?

查看:88
本文介绍了代码第一 - 当我没有将父对象设置为EntityState.Modified时,如何保存ICollection?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有以下类:

  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吗?

解决方案

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



如果你正在尝试更新 Bar 实例,你没有改变关系(=你没有添加ne w Bar Foo 或从<$ c $ < $ c> Foo )您只需要迭代 Bars 并将它们设置为修改状态



如果您还更改了 Bars 集合的内容,整个过程变得非常复杂,方法取决于您如何定义您的实体=如果您使用的是独立或外键协会



在外键关联的情况下( Bar 将FK作为property =在你有一些类似于 FooId 的东西),你按照类似的方法开始。您迭代酒吧并将状态设置为:




  • 修改如果现有的被分配到 Foo

  • 添加如果一个新的被分配到 Foo



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


  • 修改如果FK应设置为null

  • 删除如果应该被删除



这只是一对多关系。



如果您认为以前的方法很复杂,在独立关联的情况下( Bar 没有FK财产 - 永远是多对多关系的情况),过程更糟。独立关联有自己的对象跟踪状态=设置状态在 Bar 实体不持续新的关系。第一个问题是该对象不能直接从DbContext API访问 - 您必须将 DbContext 转换为 ObjectContext 并使用 ObjectStateManager 可以访问代表关系的 ObjectStateEntry 。之后,您必须正确设置其状态,因为关系不能在中修改状态 - 它只能在中保持不变添加已删除。这意味着如果您将酒吧的关系从一个更改为另一个 Foo ,则必须先找到旧关系并将其设置为已删除,然后可以将新关系设置为已添加。如果您有多对多的关系,并且您还想添加,删除和更新相关的对象(不仅仅是关系),这可能真的是大有趣 - 特别是事实上,你必须保持信息变化是什么能够正确设置所有状态。



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



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




  • 对附加对象图进行更改 - 这意味着您将首先附加原始状态实体图到上下文,然后您将进行所有更改。

  • 加载原始对象图,并手动将新图形中的所有更改合并到已加载(和附加)图表。

  • 在ObjectContext API的情况下,您可以使用自我跟踪实体,它们能够跟踪状态并自动设置应用于上下文的所有内容。他们还有一些其他缺点和限制(例如他们不支持延迟加载),并且它们不适用于DbContext API。


If I have the below class:

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

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

When saving to my db, instead of

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

I'm using

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

how can I also save changes to Bars?

解决方案

It depends what you are trying to update. First of all let me clarify one important fact - if you have detached entity graph (more entities with relation) and you want to pass all changes to EF you are responsible for telling EF what has changed in every entity and every relation - EF will not help you with it.

If you are trying to update just Bar instances and you didn't change relations (= you didn't add new Bar to Foo or removed Bar from Foo) you just need to iterate Bars and set them to Modified state.

If you also changed content of Bars collection the whole process become really complicated and the approach depends on the way how you defined your entities = If you are using independent or foreign key association.

In case of foreign key association (Bar has FK as property = in Bar you have something like FooId) you follows similar approach as at the beginning. You iterate Bars and set state to:

  • Modified if an existing Bar was assigned to Foo
  • Added if a new Bar was assigned to Foo

There is one big issue. If you removed some Bar instances from Bars collection you must also attach them to the context and set their state accordingly:

  • Modified if FK should be set to null
  • Deleted if Bar should be deleted

This all is only for one-to-many relations.

If you thought that previous approach was complicated be prepared that in case of independent association (Bar doesn't have FK property - always the case for many to many relations) the process is even worse. Independent associations have their own object tracking the state = setting the state on Bar entity doesn't persist new relation. The first problem is that this object is not directly accessible from DbContext API - you must convert DbContext to ObjectContext and use ObjectStateManager to get the access to ObjectStateEntry representing the relation. After that you must correctly set its state which is not as easy as it looks like because relation cannot be in Modified state - it can be only in Unchanged, Added or Deleted. It means that if you changed the Bar's relation from one to another Foo you must first find the old relation and set it as deleted and then you can set the new relation as added. If you have many-to-many relation and you also want to add, delete and update related objects (not only relations) this can be really "big fun" - especially the fact that you must somewhere keep the information what has changed to be able to set all states correctly.

More discussion about this problem (global in EF) is here - it is not related to the DbContext API but because the new API is just wrapper of the old ObjectContext API same problems remain.

Do you think it is feasible? I don't think so. Because of that you should try to avoid this. There are some ways how to avoid it:

  • Make changes on attached object graph - it means that you will first attach the original state of the entity graph to the context and then you will do all your changes.
  • Load the original object graph and manually merge all changes from the new graph to the loaded (and attached) one.
  • In case of ObjectContext API you can use Self-tracking entities which are able to track the state and automatically set everything with applied to the context. They have some other disadvantages and limitations (for example they don't support lazy loading) and they are not available for DbContext API.

这篇关于代码第一 - 当我没有将父对象设置为EntityState.Modified时,如何保存ICollection?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆