RPM*_*984 13 asp.net-mvc repository poco entity-framework-4
我在Review和Recommendations之间有一个*..*的关系.
我模型的相关部分(也是EF4映射的POCO):
public class Review
{
public ICollection<Recommendations> Recommendations { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在编辑视图中,我将建议书表示为一组复选框.
当我尝试添加新建议书作为编辑评论的一部分时(例如,检查另一个框),什么也没发生 - 我知道为什么......
我使用"存根技术"来更新我的实体 - 例如,我创建一个具有相同密钥的实体,将其附加到图形,然后执行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();
}
Run Code Online (Sandbox Code Playgroud)
UserContentService
public void Update<TPost>(TPost post) where TPost : Post, new()
{
_repository.Update(post); // GenericRepository<Post>
}
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
所以,Update(或Add或Delete)库的方法需要调用对每一项建议,这取决于它的新的/修改/删除.
我已经接受了@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
}
Run Code Online (Sandbox Code Playgroud)
而已.我甚至不需要我的_service.Update方法 - 因为我不再需要存根技巧 - 因为审查是在带有检索的图形中,并被ApplyCurrentValues替换为TryUpdateModel.
现在当然 - 这不是一个并发防范的解决方案.
如果我加载评论编辑视图,在我点击"提交"之前,其他人更改了评论,我的更改可能会丢失.
幸运的是,我有一个"最后赢"的并发模式,所以这对我来说不是问题.
我喜欢POCO,但是当你拥有无状态环境(MVC)和没有变化跟踪的组合时,他们是一种痛苦.
使用分离的对象图是我最喜欢的EF缺点.只是痛苦的屁股.首先,你必须自己处理它.EF不会帮助你.这意味着除了Review你还必须发送一些有关所做更改的信息.当您附加Review到上下文时,它将Review所有Recommendation和所有关系设置为Unchanged状态.ApplyCurrentValues仅适用于已经找到的标量值.所以,你必须使用有关所做的更改您的附加信息,并设置关系的状态来Added使用ObjectContext.ObjectStateManager.ChangeRelationshipState.
我个人放弃了这种方法,我正在从DB加载对象图,首先将我的更改合并到附加图中并保存.
我回答类似的问题更深入地在这里.
也许我需要更多背景信息,但有什么问题:
recommendations.Add(newRecomendation)
Run Code Online (Sandbox Code Playgroud)
?
回复评论:
好吧,那有什么问题吗
SomeServiceOrRepository.AddNewRecommendation( newRecommendation )
Run Code Online (Sandbox Code Playgroud)
或者
SomeServiceOrRepository.AddNewRecommendation( int parentId, newRecommendation )
Run Code Online (Sandbox Code Playgroud)
最后一句话?你是说这两个问题吗?
这应该不难。
总结我的答案,我认为您正在“以困难的方式”做事,并且确实应该专注于发布与您试图完成的 CRUD 操作相对应的表单值。
如果一个新实体可以与您编辑的实体同时出现,您实际上应该为它们添加不同的前缀,以便模型绑定器可以识别它。即使您有多个新项目,您也可以使用相同的 [0] 语法,只需在“名称”字段前添加 New 或其他内容即可。
很多时候,在这种情况下,您不能依赖实体框架图形功能,因为从集合中删除实体并不意味着应该将其设置为删除。
如果表单是不可变的,您还可以尝试使用 ObjectSet 的通用附加函数:
theContect.ObjectSet<Review>().Attach( review )
Run Code Online (Sandbox Code Playgroud)
有很多方法可以摆脱这种情况。也许您可以发布您的控制器并查看代码?
| 归档时间: |
|
| 查看次数: |
9893 次 |
| 最近记录: |