6

在 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 异常并向用户报告出了什么问题以及为什么?

谢谢,

马特

4

4 回答 4

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. 什么都不做就吞掉异常,这很少是个好主意

您没有任何实际选项来处理此方法中的异常。假设 UI 调用了这个方法,它应该在自己的 try..catch 中调用它,并通过向用户显示一个有意义的错误消息来处理它。您可以使用 ExpectedException(type) 属性使您的单元测试通过。

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

于 2009-04-09T23:52:21.990 回答
2

所有 Nhibernate 异常都是不可恢复的,如果您试图从 nhibernate 异常中恢复,您可以重新审视应用程序/数据层的设计。您还可以查看 spring.net 的异常翻译实现 此外,您手动处理异常事务是乏味且容易出错的,请查看nhibernate 的上下文会话。Spring.net 也有一些关于 nhibernate 的好帮手。

于 2009-04-10T00:12:34.500 回答
1

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

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

如果用户有时会是某种 UI,那么您可能希望向用户显示一条消息,但是您会告诉用户什么让他可以对此做些什么呢?例如,不管是什么原因,大多数网站都会说“抱歉,我们遇到了意外错误”。那是因为用户通常对错误无能为力。

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

于 2009-04-09T23:29:38.223 回答
1

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

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

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

于 2009-12-19T23:39:03.720 回答