Как мне обработать NHibernate, выдавая «NonUniqueObjectReferenceException», когда я обновляю сущность? - PullRequest
0 голосов
/ 08 февраля 2012

Я использую ISession.Query<T>().ToList() для получения списка объектов, добавляю их в ComboBox, чтобы пользователь мог просматривать все объекты, а затем я редактирую один из них и вызываю ISession.Update() с этим объектом. Однако это бросает NonUniqueObjectReferenceException.

Почему это происходит и какой подход я должен использовать, чтобы избежать / исправить это?

Ответы [ 4 ]

2 голосов
/ 13 февраля 2012

Объяснение проблемы

Когда вы загружаете объект, Session отслеживает первичный ключ базы данных для объекта, а также объект объекта reference (расположение в памяти) - на время действияSession.

NonUniqueObjectReferenceException выдается, если вы пытаетесь сохранить сущность, имеющую тот же первичный ключ, но другой объект reference, как уже загруженную сущность для этого Session.

Другими словами, Session говорит вам: «У меня есть объект в памяти с тем же первичным ключом, что и объект, который вы пытаетесь сохранить, но объект reference моей копии не соответствует вашей копии. "

Пример проблемы

  1. Открыть Session ( # 1 ).
  2. Загрузить объект ( ссылка на объект)= A , первичный ключ в базе данных = 1 ).
  3. Закрыть Session.
  4. Открыть новый Session( # 2 ).
  5. Повторно загрузить тот же объект (на этот раз ссылка на объект = B , первичный ключ в базе данных = 1).
  6. Измените свойство объекта A и сохраните его внутри Session # 2.
  7. NonUniqueObjectReferenceException будет брошено.

Стоит отметить, что это исключение будет выдано, даже если объект A является просто частью более крупного графа объектов, который сохраняется в сеансе №2 (даже если объект A не изменился).

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

Важное примечание: Эта проблема может быть вызвана другими способами, например, может быть вызвана с помощьюsingle Session, если вы загружаете, а затем клонируете объект, а затем используете этот клон, чтобы сохранить некоторые изменения, используя Session.Причина в том, что объект клона reference будет отличаться от исходного объекта.

Объяснение решения

Для объекта Session существует метод с именем Merge:

object Session.Merge(object obj)

Merge будет принимать сущность и, используя первичный ключ сущности, извлекать уже загруженную версию этой сущности из текущего Session.Он также обновит свойства уже загруженного объекта Session, если они отличаются от объекта, который вы только что передали.

Этот метод не изменяет объект, который вы передаете, но вместо этого возвращает другой объект, который вы должны использовать.

Последнее замечание по поводу Merge состоит в том, что если в Session, в котором вы находитесь, нет загруженной копии этого объекта в памяти, Merge пойдет вперед и загрузит объект из базы данных перед выполнением его обычной функции объединения.

Пример решения

// using the example above, we are at the beginning of step 6 inside session #2
// we have 2 important objects = ISession sessionTwo, Option objectA.
// Option is an entity defined by you, it is not part of NH.

objectA.SomeProperty = "blah";
var optionFromSessionTwo = (Option) sessionTwo.Merge(objectA);

// this will not throw and it will persist the changes to objectA
sessionTwo.Flush();

Надеюсь, это поможет!

0 голосов
/ 08 февраля 2012

session.Update() не обновляет сущность, сессия делает это прозрачно.Методы Update и Save не связаны с INSERT и UPDATE, вместо этого Save() делает временный объект постоянным, тогда как Update() делает отдельный объект постоянным.

0 голосов
/ 13 февраля 2012

Метод обновления, как указано Денисом, используется для сохранения открепленных объектов. Это исключение выдается, вероятно, из-за того, что вы пытаетесь использовать Update() для тех объектов, которые вы, вероятно, уже имели в сеансе. Вы должны использовать транзакцию или Flush() для обновления ваших объектов, если вы уже это сделали; удаление session.Update() из вашего кода должно сделать это.

Вот соответствующая часть в документации NHibernate .

0 голосов
/ 08 февраля 2012

Вам необходимо прочитать документацию по:

  • Как использовать NHibernate на Winforms
  • Что означает «обновление».

Быстрое решение: не звоните session.Update(), просто звоните session.Flush(), чтобы изменения отражались в БД.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...