ASP.NET MVC / EF4 / POCO / Repository

我在ReviewRecommendations之间建立了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> ):
  • RecommendationOne( Recommendation
  • 推荐两个( Recommendation
  • 如果在编辑视图中,则两个复选框已被选中。 第三个(代表RecommendationThree)没有被选中

    但是,如果我检查该框,上述模型将变为:

    评论:

  • 建议( ICollection<Recommendation> ):
  • RecommendationOne( 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 (或AddDelete )存储库方法,具体取决于它的新增/修改/删除。


    也许我需要更多的上下文,但什么是错的:

    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

    上一篇: ASP.NET MVC / EF4 / POCO / Repository

    下一篇: Eclipse Mylyn to GitHub connector on Eclipse Luna