这是场景:

  • ASP.NET MVC2 Web 应用程序
  • Entity Framework 4(纯 POCO,自定义数据上下文)
  • 存储库模式
  • 工作模式单元
  • 依赖注入(inject)
  • 服务层中介 Controller -> 存储库

  • 所以基本上,所有很酷的东西。 :)

    基本 UI 操作的事件流(“添加帖子”):
  • Controller 调用 Add(Post) 服务层方法
  • 服务层调用 Add(T) 在存储库
  • 存储库调用 AddObject(T) 在自定义数据上下文
  • Controller 调用 Commit() 在工作单元上

  • 现在,我正在努力找出可以将验证放在哪里。

    在这个阶段,我需要两种类型的验证:
  • 简单、独立的 POCO 验证,例如“帖子必须有标题”。这似乎很适合 POCO 上的 Data Annotations
  • 复杂的业务验证,例如“无法向锁定的帖子添加评论”。这不能通过数据注释来完成。

  • 现在,我一直在阅读 Julie Lerman 撰写的“Programming Entity Framework, Second Edition”(顺便说一句,很棒),并且一直在研究 Hook SavingChanges 事件以执行“最后一刻”验证。这将是确保验证 总是 的好方法,每当我做“某事”(添加、修改、删除)时都会发生,但这也有点晚了 IMO(因为这些项目已经在状态管理器中) - 那我能怎么办如果验证失败,删除它们?

    我当然可以让我的 POCO 实现一个接口(interface)(比如“IValidatable”),并在这个事件期间调用这个接口(interface)上的一个方法。

    但这对于业务验证来说似乎“为时已晚”——这是共识吗?

    我基本上是在这里寻找指导,鉴于我的上述架构,我正在尝试为复杂的业务逻辑设计一个可重用的智能验证方案。

    另一个曲线球 - 如您所知,带有 EF 的 POCO 意味着 POCO 具有数据库上的所有属性 - 所以我可能有一个“PostID”属性,带有获取/设置访问器(因为 EF 需要获取/设置这些属性)。

    但问题是,“PostID”是一个 标识 列,那么我如何保护该字段不被显式设置?例如,如果我(出于某种原因)执行以下操作:
    var post = service.FindSingle(10);
    post.PostId = 10;
    unitOfWork.Commit();
    

    这将抛出一个 SqlException。我怎样才能防止这种情况?我无法“隐藏”该属性(使其成为私有(private)的,甚至是内部的),因为 POCO 位于存储库的单独程序集中。

    关于验证的说明 - 我计划创建自定义异常(从异常派生)。所以当验证失败时,我需要抛出这些异常。

    这样,我可以在我的 Controller 上编写这样的代码:
    [HttpPost]
    public ActionResult AddPost(Post post)
    {
       try
       {
          IUnitOfWork uow = new UnitOfWork();
          postService.Add(post);
          uow.Commit();
       }
       catch(InvalidPostOperation ipo)
       {
          // add error to viewmodel
       }
    }
    

    每次执行 Add 时,我都必须手动对服务层进行验证吗?那我该如何处理保存呢? (因为这是在工作单元上,而不是在服务层上)。

    因此,为了防止这是一个“无处不在”的问题,以下是我的问题:
  • 简单的 POCO 验证 - 这应该用数据注释来完成吗?优点/缺点/问题?
  • 在什么情况下(如果有),我们应该挂入 EF 数据上下文的 SavingChanges 事件以提供验证?
  • 我应该在哪里执行复杂的业务验证?在服务 中明确为 ,或 POCO 上的方法(我可以从服务中调用)。我如何创建一个智能/可重用的方案?
  • 我们如何“隐藏”POCO 的自动生成属性不被篡改?

  • 任何想法将不胜感激。

    如果这篇文章“太长”,请道歉,但这是一个重要的问题,可以通过多种方式解决,所以我想提供所有信息,以便获得最佳答案。

    谢谢。

    编辑

    以下答案很有帮助,但我仍在(理想情况下)寻找更多想法。还有谁?

    最佳答案

  • 就像你说的,DataAnnotations 并不适合所有情况。根据我的经验,缺点主要是复杂的验证(多个属性和多个属性不同的对象)。
  • 如果我是你,我会尽可能地将业务/域验证排除在数据层 (EF) 之外。如果有数据层验证场景,那么很好(例如验证复杂的父/子关系 - 这纯粹是 DB 的东西)。
  • 是的,复杂的业务验证应该在服务层或模型对象中(附加,通过部分类或一些继承方法:接口(interface)/派生类)。 ActiveRecord 人员、Repository Pattern 人员和 DDD 人员之间对此存在争论,但是选择适合您的方法,这很简单,并且可以实现快速部署和低成本应用程序维护。这是一个简单的 example of how you might attach more complex validation to domain objects 但仍然与 DataAnnotations 接口(interface)兼容,因此是“MVC 友好的”。
  • 好问题。 - 我还没有找到我 100% 满意的解决方案。我玩过私有(private)二传手的想法,但并不好。快速阅读这个 summarized Evans DDD book 。它非常适合快速阅读,它可能会提供一些有关模型对象和值对象之间的目的和区别的见解。这就是我认为对象设计将减轻您对属性“篡改”(正如您所说的那样)但不修复属性可见性的问题的地方。即,另一种解决方案可能存在于其他地方。希望这可以帮助。
  • 关于asp.net-mvc - 使用 ASP.NET MVC/Entity Framework 进行 POCO 验证的建议,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3878112/

    10-17 01:59