NHibernate:如何使用每个请求的会话模式处理基于实体的验证,而控制器不知道ISession

时间:2010-03-08 17:47:27

标签: asp.net-mvc nhibernate

在ASP.NET MVC中执行基于实体的验证(每个实体类具有验证其内部成员的IsValid()方法)的最佳方法是什么,具有“每个请求的会话”模型,< strong>控制器对ISession的了解是否为零(或有限)?这是我正在使用的模式:

  1. 使用包含当前NH会话的IFooRepository按ID获取实体。这将返回一个连接的实体实例。

  2. 加载具有可能无效数据的实体,来自表单帖子。

  3. 通过调用其IsValid()方法验证实体。

  4. 如果有效,请致电IFooRepository.Save(entity),代表ISession.Save()。否则,显示错误消息。

  5. 会话当前在请求开始时打开,在请求结束时刷新。由于我的实体已连接到会话,因此即使对象无效,刷新会话也会尝试保存更改

    在实体类中保留验证逻辑的最佳方法是什么,限制控制器对NH的了解,并避免在请求结束时保存无效更改?


    选项1:显式清除验证失败,隐式刷新:如果验证失败,我可以手动驱逐操作方法中的无效对象。如果成功,我什么都不做,会话会自动刷新。

    Con :容易出错并且反直觉(“我没有调用.Save(),为什么我的无效更改仍然被保存?”

    选项2:显式刷新,默认情况下不执行任何操作:默认情况下,我可以在请求结束时处理会话,仅在控制器指示成功时才刷新。我可能在我的基本控制器中创建一个SaveChanges()方法,设置一个表示成功的标志,然后在请求结束时关闭会话时查询该标志。

    Pro :如果dev忘记了此步骤[相对于选项1],则更直观地进行故障排除

    Con :我必须致电IRepository.Save(entity)' SaveChanges()

    选项3:始终使用断开连接的对象:我可以修改我的存储库以返回断开连接的/瞬态对象,并修改Repo.Save()方法以重新附加它们。

    Pro :最直观的,因为控制器不了解NH。

    Con :这会破坏我从NH获得的许多好处吗?

3 个答案:

答案 0 :(得分:2)

选项1毫无疑问。这不是反直觉,而是NH的运作方式。使用NH检索的对象是持久的,并且在刷新会话时将保存更改。调用Evict使对象成为瞬态,这正是您想要的行为。

您没有提及它,但另一种选择可能是使用Manual或Commit FlushMode。

答案 1 :(得分:0)

验证服务如何使用IsValid(或类似的)方法来验证传递给它的对象,如果失败则可以发布ValidationFailed事件。然后,当您的请求完成而不是调用会话的flush时,您可以发布RequestEnd事件。然后,您可以拥有一个侦听RequestEnd事件和ValidationFailed事件的处理程序 - 如果存在ValidationFailed事件,则不刷新会话但如果没有则刷新它。
说过我只做选项2!

答案 2 :(得分:0)

正如Mauricio和Jamie在他们的回答/评论中所指出的那样,要完全按照问题提出要求并不容易(也可能不可取)。 NH返回持久对象,因此将这些对象暴露给控制器意味着控制器负责将它们视为。我想使用延迟加载,因此暴露分离的实例将不起作用。

选项4:引入提供所需语义的新模式

这个问题的关键在于我正在使用手动滚动的类似活动记录的DAL将NH +存储库引入现有项目。我希望代码编写NH使用类似于遗留代码的模式。

我创建了一个名为UnitOfWork的新类,它是ITransaction上的一个非常薄的包装器,它知道如何访问与当前HttpRequest相关的环境会话。此类旨在用于使用块,类似于团队熟悉的TransactionScope

using (var tx = new UnitOfWork()) {
    var entity = FooRepository.GetById(x);
    entity.Title = "Potentially Invalid Data";

    if (!entity.IsValid()) {
        tx.DiscardChanges();
        return View("ReloadTheCurrentView");
    }
    else {
        tx.Success();
        return RedirectToAction("Success");
    }
}

tx.DiscardChanges()是可选的,这个类与TransactionScope具有相同的语义,这意味着如果在设置成功标志之前将其置位,它将隐式回滚。

在绿地NH项目上,我认为最好使用选项1,正如Jamie在他的回答中所说的那样。但我认为选项4是在已经使用类似模式的遗留项目中引入NH的一种不错的方式。