pet*_*ldi 107 asp.net-mvc poco entity-framework-4
实体框架4,POCO对象和ASP.Net MVC2.我有很多关系,比如BlogPost和Tag实体之间的关系.这意味着在我的T4生成的POCO BlogPost类中,我有:
public virtual ICollection<Tag> Tags {
// getter and setter with the magic FixupCollection
}
private ICollection<Tag> _tags;
Run Code Online (Sandbox Code Playgroud)
我要求一个BlogPost和来自ObjectContext实例的相关标签,并将其发送到另一层(MVC应用程序中的View).稍后我回到更新的BlogPost,更改了属性并更改了关系.例如,它具有标签"A""B"和"C",并且新标签是"C"和"D".在我的特定示例中,没有新的标签,并且标签的属性永远不会改变,因此唯一应该保存的是改变的关系.现在我需要将它保存在另一个ObjectContext中.(更新:现在我尝试在同一个上下文实例中执行,但也失败了.)
问题:我无法正确保存关系.我尝试了我发现的一切:
"不起作用"意味着在大多数情况下我使用给定的"解决方案",直到它不产生错误并至少保存BlogPost的属性.关系会发生什么变化:通常使用新的PK将标签添加到Tag表中,并且保存的BlogPost引用那些而不是原始的.当然返回的标签有PK,在保存/更新方法之前,我检查PK并且它们等于数据库中的PK,所以EF可能认为它们是新对象而那些PK是临时的.
我知道的一个问题,并且可能使得无法找到自动化的简单解决方案:当POCO对象的集合发生更改时,应该通过上面提到的虚拟集合属性发生,因为那时FixupCollection技巧将更新另一端的反向引用多对多关系.但是,当View"返回"更新的BlogPost对象时,这种情况并未发生.这意味着对我的问题可能没有简单的解决方案,但这会让我非常伤心,我会讨厌EF4-POCO-MVC的胜利:(.这也意味着EF无法在MVC环境中做到这一点,无论哪个使用EF4对象类型:(.我认为基于快照的更改跟踪应该发现更改的BlogPost与具有现有PK的标签有关系.
顺便说一句:我认为同一个问题发生在一对多的关系上(谷歌和我的同事这么说).我会在家里尝试一下,但即使这样做对我的应用程序中的六个多对多关系没有帮助:(.
Lad*_*nka 143
我们这样试试吧:
编辑:
我想我的一条评论给了你错误的希望EF会为你做合并.我对这个问题玩了很多,我的结论是EF不会为你做这件事.我想你也在MSDN上找到了我的问题.实际上,互联网上存在大量此类问题.问题是没有明确说明如何处理这种情况.那么让我们来看看问题:
问题背景
EF需要跟踪实体的更改,以便持久性知道哪些记录必须更新,插入或删除.问题是跟踪更改是ObjectContext的责任.ObjectContext只能跟踪附加实体的更改.根本不跟踪在ObjectContext外部创建的实体.
问题描述
基于以上描述,我们可以清楚地说明EF更适合于实体始终附加到上下文的连接场景 - 通常用于WinForm应用程序.Web应用程序需要断开连接的场景,其中在请求处理之后关闭上下文并且实体内容作为HTTP响应传递给客户端.下一个HTTP请求提供实体的修改内容,该内容必须重新创建,附加到新上下文并保持不变.娱乐通常发生在上下文范围之外(具有持久性无知的分层架构).
解
那么如何处理这种断开连接的场景呢?使用POCO课程时,我们有3种方法来处理变更跟踪:
单个实体的手动同步很容易.您只需要附加实体并调用AddObject进行插入,DeleteObject用于删除或将ObjectStateManager中的状态设置为Modified以进行更新.当你必须处理对象图而不是单个实体时,真正的痛苦就来了.当你必须处理独立的关联(那些不使用外键属性)和多对多关系时,这种痛苦会更加严重.在这种情况下,您必须手动同步对象图中的每个实体,还要同步对象图中的每个关系.
MSDN文档提出了手动同步作为解决方案:附加和分离对象说:
对象以Unchanged状态附加到对象上下文.如果您需要更改对象或关系的状态,因为您知道对象已在分离状态下进行了修改,请使用以下方法之一.
提到的方法是ObjectObjectManager的ChangeObjectState和ChangeRelationshipState =手动更改跟踪.类似的提议在其他MSDN文档文章中:定义和管理关系说:
如果使用断开连接的对象,则必须手动管理同步.
此外还有与EF v1相关的博客文章,它批评了EF的这种行为.
解决的原因
EF有许多"有用"的操作和设置,如Refresh,Load,ApplyCurrentValues,ApplyOriginalValues,MergeOption等.但是通过我的调查,所有这些功能仅适用于单个实体,并且仅影响标量属性(=不是导航属性和关系).我宁愿不用嵌套在实体中的复杂类型来测试这个方法.
其他提出的解决方
而不是真正的合并功能EF团队提供了一种称为自我跟踪实体(STE)的东西,它不能解决问题.首先,STE仅在相同实例用于整个处理时才起作用.在Web应用程序中,除非您将实例存储在视图状态或会话中,否则不是这种情况.由于我对使用EF非常不满意,我将检查NHibernate的功能.首先观察说NHibernate可能具有这样的功能.
结论
我将通过MSDN论坛上另一个相关问题的单一链接来结束这些假设.检查Zeeshan Hirani的答案.他是Entity Framework 4.0 Recipes的作者.如果他说不支持自动合并对象图,我相信他.
但仍有可能我完全错了,并且EF中存在一些自动合并功能.
编辑2:
正如你所看到的那样,这已经被添加到MS Connect作为2007年的建议.MS已经关闭它作为下一版本要做的事情,但实际上没有做任何事情来改善除STE之外的这个差距.
bre*_*ick 19
我找到了Ladislav上面描述的问题的解决方案.我已经为DbContext创建了一个扩展方法,它将根据提供的图形和持久图形的差异自动执行添加/更新/删除.
目前使用实体框架,您需要手动执行联系人更新,检查每个联系人是否是新的并添加,检查是否更新和编辑,检查是否已删除然后从数据库中删除它.一旦你必须在一个大型系统中为几个不同的聚合做到这一点,你就会开始意识到必须有一个更好,更通用的方法.
您可以直接访问此处的代码https://github.com/refactorthis/GraphDiff
我知道OP已经晚了但是因为这是一个非常常见的问题,所以我发布了这个以防万一.我一直在讨论这个问题,我想我得到了一个相当简单的解决方案,我所做的是:
在下面的示例中,"dataobj"和"_categories"是我的控制器接收的参数"dataobj"是我的主要对象,"_ category"是包含用户在视图中选择的类别的ID的IEnumerable.
db.Entry(dataobj).State = EntityState.Modified;
db.SaveChanges();
dataobj = db.ServiceTypes.Include(x => x.Categories).Single(x => x.Id == dataobj.Id);
var it = _categories != null ? db.Categories.Where(x => _categories.Contains(x.Id)).ToList() : null;
dataobj.Categories = it;
db.SaveChanges();
Run Code Online (Sandbox Code Playgroud)
它甚至适用于多种关系
实体框架团队意识到这是一个可用性问题,并计划在EF6之后解决它.
来自实体框架团队:
这是我们意识到的可用性问题,也是我们一直在思考的问题,并计划在后EF6上做更多的工作.我已经创建了这个工作项来跟踪问题:http://entityframework.codeplex.com/workitem/864工作项还包含一个指向用户语音项的链接 - 我鼓励你投票给它,如果你有没有这样做过.
如果这会影响您,请投票选择该功能
http://entityframework.codeplex.com/workitem/864
| 归档时间: |
|
| 查看次数: |
34350 次 |
| 最近记录: |