Как предотвратить запись изменений объекта в базу данных на Flush с помощью Castle ActiveRecord / NHibernate - PullRequest
2 голосов
/ 22 ноября 2008

Поведение NHibernate по умолчанию - запись всех изменений объектов в базу данных при вызове Session.Flush (). Он делает это независимо от того, хотите вы этого или нет.

Как мы можем предотвратить запись неверных данных в базу данных, когда нам нужно сделать что-то вроде проверки бизнес-правил или ввода?

Например ..

  • Имя клиента не является нулевым.
  • Пользователь открывает веб-браузер (без JavaScript) и удаляет имя клиента.
  • Хиты обновления.
  • Customer.Name свойство обновлено и ..
  • Customer.IsValid() называется.
  • Даже если IsValid() равно false и мы показываем сообщения об ошибках, NHibernate по-прежнему обновляет базу данных.

Ответы [ 5 ]

2 голосов
/ 24 ноября 2008

Специально для ActiveRecord: если вы не изменяете SessionScope самостоятельно, AR по умолчанию использует шаблон управления сеансом сеанс на вызов, где новый сеанс создается для каждой операции ActiveRecordMediator. Таким образом, все извлеченные вами объекты уже отключены от родительского сеанса, как только вы их извлекаете. Изменения не будут сохраняться до тех пор, пока вы не вызовете Save (или SaveAndUpdate, или даже Update), который в шаблоне сеанса на вызов создаст сеанс, присоединит объект, который вы сохраняете к этому сеансу, вызовите Save и затем удалите сеанс (вызывая сброс и, следовательно, запись изменений).

Когда вы используете AR таким образом, он делает именно то, что вам нужно (т.е. никакие изменения не записываются обратно, если вы явно не вызываете Save). Но это явно идет вразрез с ожидаемым поведением NHibernate, и вы не можете выполнять ленивую загрузку или получить много пользы от кэширования. Я использовал этот шаблон для некоторых веб-приложений, но они разработаны заранее для активной загрузки, и довольно много постоянных объектов эффективно неизменяемы и статичны и могут загружаться в массовом порядке во время запуска и кэшироваться без подключения к какому-либо сессия. Если ваше приложение не подходит для этой модели, вероятно, плохая идея - сеанс на вызов.

Поскольку вы, похоже, используете шаблон UOW, вы не можете воспользоваться этим поведением. Таким образом, вы должны либо исключить объект из сеанса NHibernate (а получить доступ к реальному экземпляру ISession на самом деле не так просто, как кажется в AR), либо изменить способ работы вашего приложения, чтобы свойства постоянных объектов фактически не изменялись. до тех пор, пока ваши бизнес-правила не будут проверены.

2 голосов
/ 22 ноября 2008

Используйте метод ISession.Evict (objectToEvict) для удаления недопустимых объектов.

См .: http://www.tobinharris.com/2007/2/3/nhibernate-faq а также http://www.surcombe.com/nhibernate-1.2/api/html/M_NHibernate_ISession_Evict.htm

1 голос
/ 24 ноября 2008

Итак, я знаю, что это полностью излишне, но вот как я это исправил.

Преобразован в NHibernate 2.0 и использовал проект NHibernate Validator для запуска моих правил проверки ввода. Я еще не обработал бизнес-правила, но думаю, что могу сделать их с помощью пользовательских правил Validator, если это не сработает, я могу использовать события nhibernate.

Поскольку я уже использовал шаблон репозитория, преобразование было невероятно простым. Это заняло около 4-5 часов, и наша модель довольно обширная. Возможность создавать файлы .xml из атрибутов AR позволила значительно сэкономить время.

1 голос
/ 22 ноября 2008

Поведение NHibernate по умолчанию - запись всех изменений объектов в базу данных при вызове Session.Flush (). Это происходит независимо от того, хотите вы этого или нет.

Если вы не хотите, чтобы NHibernate сбрасывал сессию, тогда почему вы говорите ему сбрасывать сессию? Flush() является сокращением для WriteAllChangesToObjectsToTheDatabase().

Как мы можем предотвратить запись неверных данных в базу данных, когда нам нужно сделать что-то вроде проверки бизнес-правил или ввода?

  • Проверка изменений до изменения объектов модели. Не позволяйте недопустимым объектам модели существовать в памяти (с точки зрения общедоступного API, предоставляемого вашей моделью, и исключая сценарии многопоточности).
  • Оберните ваши изменения в транзакции, которая завершится неудачей, если проверка объектов вашей модели не удалась (почему вы допускаете недопустимые объекты модели?)
0 голосов
/ 22 ноября 2008

Вы также можете использовать сессию с FlushAction.Never. То есть:

SessionScope session = new SessionScope(FlushAction.Never);

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

...