处理NHibernate异常

处理NHibernate异常,nhibernate,exception,exception-handling,unique-constraint,Nhibernate,Exception,Exception Handling,Unique Constraint,在NHibernate中处理异常的最佳实践是什么 我有一个主题库,其中包含以下内容: public void Add(Subject subject) { using (ISession session = HibernateUtil.CurrentSession) using (ITransaction transaction = session.BeginTransaction()) { session

在NHibernate中处理异常的最佳实践是什么

我有一个主题库,其中包含以下内容:

    public void Add(Subject subject)
    {
        using (ISession session = HibernateUtil.CurrentSession)
        using (ITransaction transaction = session.BeginTransaction())
        {

            session.Save(subject);
            transaction.Commit();
        }
    }
以及如下所示的单元测试:

        [Test]
    public void TestSaveDuplicate()
    {
        var subject = new Subject
        {
            Code = "En",
            Name = "English"
        };

        _subjectRepository.Add(subject);

        var duplicateSubject = new Subject
        {
            Code = "En",
            Name = "English1"
        };

        _subjectRepository.Add(duplicateSubject);
    }
我着手处理单元测试产生的错误,但有点卡住了。这会像预期的那样失败,尽管使用GenericADOException时,我预期会出现ConstraintViolationException或类似的情况(数据库级别的主题代码上存在唯一性约束)

ADOException封装了一个MySQL异常,该异常有一条合理的错误消息,但我不想通过抛出内部异常来破坏封装。特别是MySQL还没有最终确定为这个项目的后端

理想情况下,我希望能够捕获异常并在此时向用户返回一个合理的错误。是否有任何记录在案的最佳实践方法来处理NHibernate异常并向用户报告出了什么问题以及原因

谢谢


Matt

一般的问题是,你想告诉用户什么,用户是谁

如果用户有时是另一台计算机(即,这是一个web服务),那么您需要使用适当的机制来返回SOAP错误或HTTP错误

如果用户有时是某种类型的UI,那么您可能希望向用户显示一条消息,但是您会告诉用户什么,以便他可以对此做些什么?例如,无论原因是什么,大多数网站都会说,“对不起,我们发生了意外错误”。这是因为用户通常对错误无能为力


但是在这两种情况下,选择如何告诉“用户”是表示层(UI层)的问题,而不是DAL的问题。您可能应该将DAL中的异常包装为另一种异常类型,但前提是您要更改消息。您不需要自己的异常类,除非调用方在数据访问异常而不是其他类型的异常时会执行不同的操作。

public void Add(Subject subject)
{
    using (ISession session = HibernateUtil.CurrentSession)
    using (ITransaction transaction = session.BeginTransaction())
    {
        try
        {
            session.Save(subject);
            transaction.Commit();
        }
        catch (Exception ex)
        {
            transaction.Rollback();
            // log exception
            throw;
        }
    }
}
在catch块中,您应该首先回滚事务并记录异常。那么你的选择是:

  • 重新显示相同的异常,这就是我的版本所做的
  • 将它包装在您自己的异常中并抛出它
  • 什么都不做就可以吞下例外,这很少是个好主意
  • 在此方法中,您没有任何处理异常的实际选项。假设UI调用此方法,它应该在自己的try..catch中调用它,并通过向用户显示有意义的错误消息来处理它。您可以使用ExpectedException(type)属性使单元测试通过


    为了直接回答您的问题,您应该通过扩展异常创建自己的“可感知错误”,并将原始异常作为其内部异常抛出。这就是我在(2)中列出的异常包装技术。

    所有Nhibernate异常都是不可恢复的,如果您试图从Nhibernate异常中恢复,您可以重新考虑应用程序/数据层的设计。 你也可以看看spring.net的 另外,手动处理异常事务非常繁琐且容易出错,请参阅。
    在nhibernate附近,Spring.net也有一些很好的助手。

    我可能会在保存对象之前验证输入;这样,您就可以实现您喜欢的任何验证(例如,检查主题代码的长度以及没有任何重复的事实),并将有意义的验证错误传递回用户

    逻辑如下;异常用于表示您的程序不适合的异常情况。在上面的示例中,用户输入重复的主题代码是您的程序应该满足的;因此,您不希望因为DB约束被违反而处理异常(这是一个异常事件,不应该发生),而是希望首先处理该场景,并且只在知道所保存的数据正确时才尝试保存数据


    在DAL中实现所有验证规则的好处是,您可以确保进入数据库的数据按照业务流程以一致的方式有效,而不是依赖数据库中的约束来为您捕获这些约束。

    我认为包装异常也是最好的选择。内部异常类似于MySQLException Message=“键3的重复条目‘En’”。由于这将由前端直接调用,因此我想返回一条有意义的消息。如果只是重新引发异常,则可以删除大部分代码——如果事务未显式提交,则在会话关闭时将回滚(或者如果提交调用引发异常,则会尝试回滚),因此,只要让异常消失,NH将处理未提交的事务——您将使用更干净的代码获得相同的效果。NHibernate的conextual会话的链接已断开。从archive.org使用NHibernate的conextual会话的链接: