处理NHibernate异常

时间:2009-04-09 22:33:55

标签: nhibernate exception exception-handling unique-constraint

在NHibernate中处理异常的最佳做法是什么?

我有一个带有以下内容的SubjectRepository:

    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 Exceptions并向用户报告出错的原因以及原因?

谢谢,

马特

4 个答案:

答案 0 :(得分:13)

我会在Add方法中处理它:

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块中,您应首先回滚事务并记录异常。那你的选择是:

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

    要直接回答您的问题,您应该通过扩展Exception来创建自己的“明智错误”,并将原始异常作为InnerException抛出。这是我在(2)中列出的异常包装技术。

答案 1 :(得分:2)

所有Nhibernate异常都是不可恢复的,如果您尝试从nhibernate异常中恢复,则可以重新访问app / data层的设计。   你也可以看一下spring.net的exception translation implementaion 此外,您手动处理异常事务是单调乏味且容易出错的,请查看nhibernate's contextual sessions。 Spring.net也有一些关于nhibernate的好帮手。

答案 2 :(得分:1)

一般问题是,您想告诉用户什么,以及谁是用户?

如果用户有时会是另一台计算机(即,这是一个Web服务),那么您可能希望使用适当的机制来返回SOAP Fault或HTTP错误。

如果用户有时会成为某种类型的用户界面,那么您可能希望向用户显示一条消息,但是您会告诉用户他可以对此做些什么?例如,无论出于什么原因,大多数网站都会说“抱歉,我们遇到了意想不到的错误”。那是因为用户通常无法对错误做任何事情。

但无论如何,选择如何告诉“用户”是表示层(UI层)的问题,而不是DAL的问题。您应该在另一个异常类型中将DAL中的异常包装起来,但前提是您要更改消息。你不需要你自己的异常类,除非你的调用者会做一些不同的事情,如果它是一个数据访问异常而不是其他类型。

答案 3 :(得分:1)

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

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

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