NHibernate: как обрабатывать валидацию на основе сущностей с использованием шаблона сеанса на запрос, при этом контроллеры не знают об ISession - PullRequest
3 голосов
/ 08 марта 2010

Каков наилучший способ проверки на основе сущностей (каждый класс сущностей имеет метод IsValid(), который проверяет своих внутренних членов) в ASP.NET MVC с моделью «сеанс на запрос», где контроллер имеет нулевое (или ограниченное) знание ISession ? Вот образец, который я использую:

  1. Получить сущность по ID, используя IFooRepository, который оборачивает текущий сеанс NH. Возвращает экземпляр подключенной сущности.

  2. Загрузка объекта с потенциально недействительными данными, поступающими из сообщения формы.

  3. Подтвердите сущность, вызвав ее IsValid() метод.

  4. Если действительно, звоните IFooRepository.Save(entity), который делегирует ISession.Save(). В противном случае выведите сообщение об ошибке.

Сессия в настоящее время открывается, когда начинается запрос, и сбрасывается, когда запрос заканчивается . Поскольку моя сущность подключена к сеансу, очистка сеанса пытается сохранить изменения , даже если объект недействителен .

Каков наилучший способ сохранить логику проверки в классе сущности, ограничить знания контроллера NH и избежать сохранения недопустимых изменений в конце запроса?


Вариант 1: явное исключение при сбое проверки, неявное сбрасывание : в случае сбоя проверки я могу вручную удалить недействительный объект в методе действия. В случае успеха я ничего не делаю и сеанс автоматически сбрасывается.

Con : подвержен ошибкам и нелогичен ( "Я не вызывал .Save (), почему все равно мои неверные изменения сохраняются?" )

Вариант 2. Явно сбрасывать, по умолчанию ничего не делать : По умолчанию я могу избавиться от сеанса по окончании запроса, только сбрасывая, если контроллер указывает на успех. Вероятно, я бы создал метод SaveChanges() в моем базовом контроллере, который устанавливает флаг, указывающий на успех, а затем запросил бы этот флаг при закрытии сеанса в конце запроса.

Pro : более интуитивно понятный способ устранения неполадок, если dev забывает этот шаг [относительно опции 1]

Con : мне нужно позвонить IRepository.Save(entity) ' и SaveChanges().

Вариант 3: Всегда работать с отключенными объектами: Я мог бы изменить свои репозитории, чтобы они возвращали отключенные / временные объекты, и изменить метод Repo.Save() для их повторного присоединения.

Pro : Наиболее интуитивно понятный, учитывая, что контроллеры не знают о NH.

Con : Это наносит ущерб многим из преимуществ, которые я получу от NH?

Ответы [ 3 ]

2 голосов
/ 10 марта 2010

Вариант 1 без сомнения. Это не противоречит интуиции, это то, как работает NH. Объекты, извлеченные с помощью NH, являются постоянными, и изменения будут сохранены при сбросе сеанса. Вызов Evict делает объект переходным, и это именно то поведение, которое вам нужно.

Вы не упоминаете об этом, но другим вариантом может быть использование Manual или Commit FlushMode.

0 голосов
/ 10 марта 2010

Как указали Маурисио и Джейми в своих ответах / комментариях, нелегко (и, вероятно, нежелательно) делать именно то, что задает вопрос. NH возвращает постоянные объекты, поэтому предоставление этих объектов контроллерам означает, что контроллеры несут ответственность за их обработку как таковую . Я хочу использовать отложенную загрузку, чтобы не показывать отдельные экземпляры.

Вариант 4: введите новый шаблон, обеспечивающий желаемую семантику

Смысл этого вопроса в том, что я представляю NH + Repositories в существующий проект, используя DAL, подобный Active-Record. Я хочу, чтобы в написанном коде 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, что означает, что он будет неявно откатываться, если он будет удален до установки флага успеха.

В новом проекте NH я думаю, что предпочтительнее использовать Вариант 1, как указывает Джейми в своем ответе. Но я думаю, что Вариант 4 - достойный способ представить NH в старом проекте, который уже использует подобные шаблоны.

0 голосов
/ 08 марта 2010

Как насчет службы проверки с помощью метода IsValid (или чего-то подобного), который проверяет объект, переданный ему, в случае неудачи он может опубликовать событие ValidationFailed.Затем, когда ваш запрос завершится вместо вызова сброса сеанса, вы можете опубликовать событие RequestEnd.Тогда у вас может быть обработчик, который прослушивает как события RequestEnd, так и события ValidationFailed - если есть событие ValidationFailed, то не сбрасывайте сеанс, но если нет, то очищайте его.
Сказав, что я просто делаю Вариант 2!

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