Короткий ответ: версия - это свойство, которым управляет NHibernate. Вы можете изменить его, но ваши изменения игнорируются. Как вы обнаружили, один из способов сделать изменения - это удалить объект, а затем снова прикрепить / сохранить / обновить. Из-за изгнания NHibernate забывает, какова его ценность для версии, которая заставляет его получать его от объекта. (Возможно, я здесь слишком упрощен.)
Эта проблема уже поднималась. Множество людей спрашивают, почему кто-то хотел бы сделать это - один действительный сценарий - веб-приложение без состояния. Каждый HTTP-запрос создает свой собственный сеанс NHibernate, который умирает, когда запрос выполнен. Может быть запрошена страница, которая показывает частичные детали объекта для редактирования. Идентификатор и версия хранятся в скрытых полях. В postpack (который является новым запросом, только с данными на этот раз) новый сеанс NHibernate перезагружает рассматриваемый объект, применяет изменения из данных формы, включая версию, а затем сохраняет объект. Изменение версии здесь в этом сценарии полностью допустимо. Если кто-то еще изменил тот же объект между первоначальным запросом и обратной передачей, эти изменения не должны быть перезаписаны. Исключение устаревшего объекта должно быть вызвано, но не будет, потому что изменение версии игнорируется NHibernate.
Мне известны два способа исправления ошибки в версии для подобных сценариев. Одним из них является метод выселения, уже проиллюстрированный ОП. Второе - создать перехватчик NHibernate для перехвата операций обновления и проверки версии вручную.
Здесь обсуждается этот вопрос и два решения.
https://forum.hibernate.org/viewtopic.php?t=977889
Я использую перехватчик, модифицированный из приведенного здесь кода.
http://weblogs.asp.net/stefansedich/archive/2008/10/01/set-the-value-of-a-version-column-in-nhibernate-manually.aspx
Внутренности моего перехватчика выглядят немного иначе (я использую NHibernate 2.1.2.4000).
private void CheckVersion(object domainObject, object uid)
{
ISessionImplementor sessionImpl = Session.GetSessionImplementation();
IEntityPersister persister = sessionImpl.GetEntityPersister(null, domainObject);
if (persister.IsVersioned)
{
EntityMode mode = Session.GetSessionImplementation().EntityMode;
object version = persister.GetVersion(domainObject, mode);
object currentVersion = persister.GetCurrentVersion(uid, sessionImpl);
if (!persister.VersionType.IsEqual(version, currentVersion))
throw new StaleObjectStateException(persister.EntityName, uid);
}
}