代码之家  ›  专栏  ›  技术社区  ›  Seth Petry-Johnson

nhibernate:如何使用session-per-request模式处理基于实体的验证,而不让控制器知道isession

  •  3
  • Seth Petry-Johnson  · 技术社区  · 15 年前

    执行基于实体的验证的最佳方法是什么(每个实体类都有一个 IsValid() 方法验证其内部成员),在asp.net mvc中,使用“session per request”模型, 如果控制器对ISession的知识为零(或有限) ?下面是我使用的模式:

    1. 使用 IFooRepository 结束了当前的nh会话。这将返回一个连接的实体实例。

    2. 从表单post加载具有潜在无效数据的实体。

    3. 通过调用 ISVALSE() 方法。

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

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

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


    选项1:验证失败时显式收回,隐式刷新 :如果验证失败,我可以手动逐出action方法中的无效对象。如果成功,则不执行任何操作,会话将自动刷新。

    反对的论点 :容易出错且违反直觉( “我没有调用.save(),为什么总是保存我的无效更改?” )

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

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

    反对的论点 :我必须打电话 IRepository.Save(entity) 保存更改() .

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

    赞成 :最直观的,因为控制器不知道NH。

    反对的论点 :这是否击败了我从NH获得的许多好处?

    3 回复  |  直到 15 年前
        1
  •  2
  •   Jamie Ide    15 年前

    毫无疑问,选择1。这不是违反直觉,而是NH的工作原理。使用nh检索的对象是持久的,刷新会话时将保存更改。调用exict会使对象成为暂时的,这正是您想要的行为。

    您没有提到它,但是另一个选项可能是使用手动或提交flushmode。

        2
  •  0
  •   Gareth    15 年前

    使用isvalid(或类似的)方法验证传递给它的对象,如果失败,它可以发布validationfailed事件。然后,当您的请求完成而不是调用会话的flush时,您可以发布一个requestend事件。然后可以有一个处理程序同时侦听requestEnd事件和validationFailed事件-如果有validationFailed事件,则不刷新会话,但如果没有,则刷新会话。
    我说过我只做选择2!

        3
  •  0
  •   Seth Petry-Johnson    15 年前

    正如莫里西奥和杰米在他们的回答/评论中所指出的那样,要准确地回答问题并不容易(可能也不可取)。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具有相同的语义,这意味着如果在设置成功标志之前释放它,它将隐式回滚。

    在新罕布什尔州的一个新建项目中,我认为最好使用选项1,正如杰米在他的回答中指出的那样。但我认为选项4是一个很好的方法,可以在已经使用类似模式的遗留项目上引入nh。