Ответ 1
Для некоторых объектов вы можете создать недопустимое состояние, но динамические обновления. Скажем, у вас есть Class
с Boolean
Свойством A
и логически зависимым Integer
Свойством B
. Если свойство A
равно True
, то свойство B
может быть только отрицательным числом, а если свойство A
равно False
, то свойство B
может быть только положительным числом.
Скажем, что два пользователя взаимодействуют с экземпляром этого класса за определенный промежуток времени. Для начала пользователи Alice и Bob материализуют этот класс из базы данных с начальными значениями A
= True и B
= -50
Database Alice Bob
A: True A: True A: True
B: -50 B: -50 B: -50
VALID VALID VALID
Пользователь Alice изменяет A
на False
и B
на 125 и передает его в базу данных. Теперь мы имеем следующую ситуацию:
Database Alice Bob
A: False A: False A: True
B: 125 B: 125 B: -50
VALID VALID VALID
Пользователь Bob не меняет A
, но меняет B
на -75, а затем записывает его в базу данных. Если динамические обновления включены, NHibernate видит, что Боб только изменил B
на -75 и выдает динамическое обновление, которое редактирует только значение B
. Если у вас была проверка SQL на сервере, чтобы предотвратить B
от отрицания, если только A
не было true, вы получили бы ошибку SQL здесь, но позвольте сказать, что вы не воспроизвели всю свою бизнес-логику в своих таблицах SQL. Вот результирующие данные:
Database Alice Bob
A: False A: False A: True
B: -75 B: 125 B: -75
INVALID VALID VALID
И у Алисы, и у Боба есть действительные состояния, но База данных теперь находится в недопустимом состоянии! Пользователь Чарли приходит и пытается материализовать эту запись:
Database Alice Bob Charlie
A: False A: False A: True A: False
B: -75 B: 125 B: -75 B: -75
INVALID VALID VALID INVALID
Charlie скорее всего получит ошибку проверки из вашего приложения, когда NHibernate попытается установить свойство B нового экземпляра вашего класса.
Итак, когда у вас есть логически зависимые свойства, у вас должна быть стратегия для избежания этой ситуации. Одна из возможностей - просто включить select-before-update
для этого объекта. Это может привести к некоторым дополнительным вызовам в базе данных и немного более низкой производительности. Другим является использование версий в NHibernate, что означало бы, что, когда Боб пытается сохранить свою запись, запрос на вставку NHibernate не будет запускать какие-либо записи и выкидывать исключение устаревшей информации (которое может быть изящно обработано). Вы также можете кодифицировать логические требования своего класса в базе данных, однако тогда вам следует быть осторожными, чтобы убедиться, что база данных и программа имеют одинаковые кодифицированные требования с течением времени, и у вас будет несколько мест для вносить изменения при изменении требований, что не всегда стоит накладных расходов.
Итак, во многих случаях разработчик должен тщательно обрабатывать детали динамических обновлений, поэтому он по умолчанию не включен. Когда вы включите его, подумайте о том, могут ли частичные обновления вашей организации создавать проблемы, и если да, используйте одну из стратегий смягчения, которые я рекомендовал защитить от этой проблемы.