2008-11-21 2 views
2

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

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

Например ..

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

ответ

2

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

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

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

2

Используйте метод 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

согласился, что работает, но затем я вызываю выселение по всему моему клиентскому коду. не идеально. –

0

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

SessionScope session = new SessionScope(FlushAction.Never); 

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

+2

Сохранить не означает «сохранить изменения». Изменения автоматически сохраняются за кулисами (это то, что делает Flush). Save изменяет состояние объекта от переходного к постоянному и каскадирует изменения, как указано в сопоставлении объекта; он не обязательно немедленно выполняет SQL. – yfeldblum

+0

Я использую это в веб-приложении, поэтому у меня нет прямого доступа к сеансу (он обрабатывается единицей работы). –

1

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

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

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

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

это приложение представляет собой веб-приложение, а сеанс обрабатывается подразделением. Он автоматически очищается после каждого веб-запроса. Как вы предлагаете мне проверять свои бизнес-объекты? Приведенный пример является тривальным, НО, другие гораздо сложнее проверить без создания объекта. –

+0

Подтвердите все данные и операции во время вызова, чтобы свойство не могло вообще измениться на что-то недействительное. Метафора NHibernate проста - постоянный объект в памяти, а данные в БД должны считаться неотъемлемыми; измените одно == измените другое. Игнорируйте сантехнику. –

1

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

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

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