ASP.NET MVC / EF4 / POCO / Repository
我在Review和Recommendations之间建立了1 .. *关系。
我的模型的相关部分(也是由EF4映射的POCO):
public class Review
{
public ICollection<Recommendations> Recommendations { get; set; }
}
在编辑视图上 ,我将这些建议表示为一组复选框。
当我尝试添加新建议书作为编辑评论的一部分时(例如,查看另一个框),没有任何事情发生 - 我知道为什么......
我使用“存根技术”来更新我的实体 - 例如,我使用相同的键创建一个实体,将它附加到图上,然后执行ApplyCurrentValues
。 但这只适用于标量属性,不适用于导航属性。
我发现这个看起来不错的StackOverflow问题,但是我正在努力解决如何使它与POCO的/ Repository(和ASP.NET MVC - 分离的上下文)一起工作。
正如我使用POCO的, review.Recommendations
是一个ICollection<Recommendation>
,所以我不能做review.Recommendations.Attach
。 我没有使用自我跟踪实体,所以我需要手动使用图形/更改跟踪 - 这直到现在还没有成为问题。
所以你可以想象这个场景:
评论:
ICollection<Recommendation>
): Recommendation
) Recommendation
) 如果在编辑视图中,则两个复选框已被选中。 第三个(代表RecommendationThree)没有被选中 。
但是,如果我检查该框,上述模型将变为:
评论:
ICollection<Recommendation>
): Recommendation
) Recommendation
) Recommendation
) 所以我需要将RecommendationThree作为一个新的实体附加到图上。
我是否需要隐藏字段比较发布的数据现有的实体? 或者,我应该将实体存储在TempData中并将其与发布的实体进行比较?
编辑
为了避免混淆,下面是完整的应用程序堆栈调用:
ReviewController
[HttpPost]
public ActionResult Edit(Review review)
{
_service.Update(review); // UserContentService
_unitOfWork.Commit();
}
UserContentService
public void Update<TPost>(TPost post) where TPost : Post, new()
{
_repository.Update(post); // GenericRepository<Post>
}
GenericRepository - 用作GenericRepository<Post>
public void Update<T2>(T2 entity) where T2 : class, new()
{
// create stub entity based on entity key, attach to graph.
// override scalar values
CurrentContext.ApplyCurrentValues(CurrentEntitySet, entity);
}
因此,需要为每个建议调用Update
(或Add
或Delete
)存储库方法,具体取决于它的新增/修改/删除。
也许我需要更多的上下文,但什么是错的:
recommendations.Add(newRecomendation)
?
回复评论:
好,那么怎么了
SomeServiceOrRepository.AddNewRecommendation( newRecommendation )
要么
SomeServiceOrRepository.AddNewRecommendation( int parentId, newRecommendation )
最后一句话? 你的意思是这两个问题?
这应该不难。
总结我的回答,我认为你是在“做的很难”,而且应该专注于张贴与你试图完成的CRUD动作相对应的表单值。
如果一个新的实体可以与您编辑的实体同时进入,您应该以不同的方式加前缀,以便模型联编程序可以接受它。 即使你有多个新项目,你也可以使用相同的[0]语法,只需在“name”字段前添加New或其他内容即可。
在这种情况下,很多时候您不能依赖实体框架图形功能,因为从集合中删除实体从不意味着它应该设置为删除。
如果表单是不可变的,你也可以尝试使用ObjectSet的基因化附加函数:
theContect.ObjectSet<Review>().Attach( review )
多种方法可以解决这个问题。 也许你可以发布你的控制器和查看代码?
我已经接受了@ jfar的回答,因为他让我走上了正确的轨道,但我认为我会在这里为其他人的利益添加一个答案。
关系没有得到更新的原因是由于以下原因:
1)完全断开的情况。 ASP.NET =无状态,新的上下文提出每个HTTP请求。
2)由MVC创建的编辑实体(模型绑定),但不存在于图中。
3)当使用POCO没有变更跟踪时,执行.Attach
实体会将其添加到图中,但实体和任何子关系都将保持不变。
4)我使用存根实体技巧和ApplyCurrentValues
更新实体,但这只适用于标量属性,不适用于导航类型。
所以 - 为了得到上面的工作,我必须明确地设置对象的EntityState
(由于ApplyCurrentValues
而自动发生) 以及导航属性。
还有问题 - 我如何知道导航属性是添加/修改/删除的? 我没有任何反对的对象 - 只有一个我知道被“编辑”的实体,但我不知道编辑过的是什么。
所以最终的解决方案是这样的:
[HttpPost]
public ActionResult Edit(Review review)
{
var existingReview = _service.FindById(review.Id); // review is now in graph.
TryUpdateModel(existingReview); // MVC equivalent of "ApplyCurrentValues" - but works for ALL properties - including navigationals
_unitOfWork.Commit(); // save changed
}
而已。 我甚至都不需要我的_service.Update
方法-因为我不需要存根招了-因为审查与检索的图形,并ApplyCurrentValues
被替换TryUpdateModel
。
当然,这不是一个并发防御解决方案。
如果我加载审阅编辑视图,并且在我点击“提交”之前其他人更改了审阅,我的更改可能会丢失。
幸运的是,我有一个“最后赢”的并发模式,所以这对我来说不是问题。
我喜欢POCO的,但是当你拥有无状态环境(MVC)和无变化追踪的组合时,他们是一种痛苦。
使用分离的对象图是我最喜欢的EF的缺点。 只是在屁股疼痛。 首先你必须自己处理它。 英孚不会帮助你。 这意味着除了Review
之外,您还必须发送一些关于所做更改的信息。 将Review
附加到上下文时,它会将Review
所有Recommendation
和所有关系设置为未Unchanged
状态。 ApplyCurrentValues
仅适用于您已经找到的标量值。 因此,您必须使用关于所做更改的附加信息,并使用ObjectContext.ObjectStateManager.ChangeRelationshipState
将关系的状态设置为Added
。
我personaly放弃了这种做法,我从DB加载对象图首先合并我的变化到附加的图形并保存它。
我在这里更深地回答了类似的问题。
链接地址: http://www.djcxy.com/p/25461.html