Почему nHibernate не выдает устаревшее состояние исключение на SaveOrUpdate, когда версия строки не совпадает? - PullRequest
4 голосов
/ 27 октября 2010

Это приводит к исключению StaleStateException:

var entity = Session.Load(id);
Session.Evict(entity);
entity.SomePropert = "Something";
entity.Version = Version--;
Session.SaveOrUpdate(entity); // Throws Exception

Это, однако, не вызывает исключения.Также ни одна строка не обновляется.

var entity = Session.Load(id);
entity.SomePropert = "Something";
entity.Version = Version--;
Session.SaveOrUpdate(entity); // Does not throw Exception, 
                              // but no rows are updated

1 Ответ

5 голосов
/ 28 октября 2010

Короткий ответ: версия - это свойство, которым управляет 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...