Обработка исключений NHibernate - PullRequest
6 голосов
/ 10 апреля 2009

Как лучше всего обрабатывать исключения в 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 Exception, у которого есть разумное сообщение об ошибке, но я не хочу начинать нарушать инкапсуляцию, просто выбрасывая внутреннее исключение. Тем более, что MySQL не является финальной частью этого проекта.

В идеале я хотел бы иметь возможность перехватить исключение и вернуть пользователю ощутимую ошибку на данном этапе. Существуют ли документированные подходы к наилучшей практике обработки исключений NHibernate и создания отчетов для пользователя о том, что пошло не так и почему?

Спасибо

Мэтт

Ответы [ 4 ]

13 голосов
/ 10 апреля 2009

Я бы обработал это в методе 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. Rethrow то же исключение, что делает моя версия
  2. Оберни это в свое собственное исключение и брось это
  3. Поглотить исключение, ничего не делая, что очень редко бывает хорошей идеей

У вас нет реальных вариантов обработки исключения в этом методе. Предполагая, что пользовательский интерфейс вызывает этот метод, он должен вызывать его в своем собственном try..catch и обрабатывать его, отображая значимое сообщение об ошибке для пользователя. Вы можете выполнить тестовый модуль, используя атрибут ExpectedException (type).

Чтобы ответить на ваш вопрос напрямую, вы должны создать свою собственную "разумную ошибку", расширив Exception, и выбросить ее с исходным исключением в качестве InnerException. Это техника исключения, которую я перечислил в (2).

2 голосов
/ 10 апреля 2009

Все исключения Nhibernate не подлежат восстановлению, вы можете вернуться к дизайну слоя приложения / данных, если вы пытаетесь восстановить после исключений nhibernate. Вы также можете взглянуть на реализацию перевода исключений в Spring.net Также ручная обработка транзакций для исключений является утомительной и подверженной ошибкам, взгляните на контекстные сеансы nhibernate . Spring.net также имеет несколько хороших помощников по nhibernate.

1 голос
/ 20 декабря 2009

Я бы, вероятно, проверил ввод перед сохранением объекта; таким образом, вы можете реализовать любую понравившуюся вам проверку (например, проверить длину кода объекта, а также тот факт, что дубликатов нет) и вернуть пользователю значимые ошибки проверки.

Логика следующая; исключения используются для обозначения исключительных обстоятельств, которые ваша программа не обслуживает. Пользователь, вводящий дубликат кода субъекта в приведенном выше примере, - это то, к чему должна стремиться ваша программа; таким образом, вместо обработки исключения, поскольку ограничение БД нарушается (что является исключительным событием и не должно происходить), вам следует сначала обработать этот сценарий и попытаться сохранить данные только тогда, когда вы знаете, что данные Экономим правильно.

Преимущество реализации всех правил проверки в вашем DAL заключается в том, что вы можете затем гарантировать, что данные, поступающие в вашу БД, действительны в соответствии с вашими бизнес-процессами согласованным образом, а не полагаться на ограничения в вашей БД, чтобы перехватить эти для вас.

1 голос
/ 10 апреля 2009

Общий вопрос будет таким: что вы хотите сказать пользователю и кто является пользователем?

Если пользователь иногда будет другим компьютером (т. Е. Это веб-служба), то вы захотите использовать соответствующий механизм для возврата ошибки SOAP или HTTP.

Если пользователь иногда будет чем-то вроде пользовательского интерфейса, то вы можете захотеть показать сообщение пользователю, но что бы вы сказали пользователю, чтобы он мог что-то с этим сделать? Например, большинство веб-сайтов скажут: «Извините, у нас произошла непредвиденная ошибка», независимо от причины. Это потому, что обычно пользователь ничего не может сделать с ошибкой.

Но в любом случае выбор того, как сказать «пользователь», зависит от уровня представления (уровня пользовательского интерфейса), а не от DAL. Возможно, вам следует заключить исключения из DAL в другой тип исключения, но только если вы собираетесь изменить сообщение. Вам не нужен ваш собственный класс исключений, если только ваши абоненты не сделают что-то другое, если это исключение доступа к данным, а не какой-либо другой тип.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...