NHibernate, DTO и NonUniqueObjectException
-
21-08-2019 - |
Вопрос
Мы используем шаблон DTO для маршалирования объектов нашего домена с уровня сервиса в наш репозиторий, а затем в базу данных через NHibernate.
Я столкнулся с проблемой, из-за которой я извлекаю DTO из репозитория (например.CustomerDTO), а затем преобразовать его в объект домена (Customer) на моем уровне обслуживания.Затем я пытаюсь сохранить новый объект обратно (например.SalesOrder), который содержит тот же объект Customer.Он, в свою очередь, преобразуется в SalesOrderDTO (и CustomerDTO) для отправки в репозиторий.
NHibernate это не нравится — он жалуется, что CustomerDTO — дублирующаяся запись.Я предполагаю, что это связано с тем, что он извлек первый CustomerDTO в том же сеансе, и поскольку возвращаемые данные преобразовывались туда и обратно, он не может распознать это как один и тот же объект.
Я застрял здесь или есть способ обойти это?
Спасибо
Джеймс
Решение
Вы можете повторно присоединить объект к сеансу в NHibernate, используя Lock - например.
_session.Lock(myDetachedObject, NHibernate.LockMode.None);
что может помочь, а может и не помочь, в зависимости от того, что именно здесь происходит.Кстати, использование DTO с NHibernate — не самая распространенная практика. Тот факт, что NHibernate (в основном) поддерживает игнорирование персистентности, означает, что обычно DTO не так широко используются, как в некоторых других платформах ORM.
Другие советы
На самом деле речь идет о том, как работает сеанс NHibernate.Итак, если вы в течение сеанса извлекаете экземпляр своего CustomerDTO, а затем через некоторое время вы должны получить тот же самый CustomerDTO (скажем, по первичному ключу) - вы фактически получите ссылку на тот же самый объект, что и при первом извлечении.
Итак, вы либо объединяете объекты, вызывая session.Merge, либо запрашиваете объект у своего сеанса, вызывая session.Get(primaryKey), выполняете обновления и очищаете сеанс.
Однако, как предложил Стив - обычно это не то, что вы делаете - вы действительно хотите получить свой объект домена из хранилища данных и использовать DTO (при необходимости) для передачи данных в пользовательский интерфейс, веб-сервис или что-то еще...
Как отмечали другие, реализация Equals и GetHashCode — это шаг в правильном направлении.Также обратите внимание на поддержку NHibernate идиомы «attach» OR/M.
В вашем распоряжении также есть опция Nosette.camelcase: http://davybrion.com/blog/2009/03/entities-required-properties-and-properties-that-shouldnt-be-modified/
Кроме того, я хотел бы призвать вас не разочаровываться из-за отсутствия информации в Интернете.Это не значит, что вы сумасшедший или делаете что-то неправильно.Это просто означает, что вы работаете в крайнем случае.К сожалению, крупнейшими потребителями таких библиотек, как NHibernate, являются небольшие собственные и/или веб-приложения, в которых существует возможность объединить все ваши потребности в постоянстве с одной базой данных.На самом деле из этого правила есть много исключений.
Например, в настоящее время я работаю над коммерческим настольным приложением, в котором данные одного из моих объектов домена распределены между базой данных SQL CE и файлами изображений на диске.К сожалению, NHibernate может помочь мне только с сохранением SQL CE.Я вынужден использовать своего рода «двойное сопоставление» (см. Мартин Фаулер «Образцы архитектуры корпоративных приложений».) сопоставьте мою модель домена через уровень репозитория, который знает, какие данные поступают в NHibernate, а какие на диск.
Бывает.Это реальная необходимость.Иногда очевидный недостаток инструмента указывает на то, что вы применяете плохой подход.Но иногда правда в том, что вы действительно находитесь в крайнем случае, и вам нужно выработать некоторые из этих шаблонов для себя, чтобы добиться цели.
Я предполагаю, что это потому, что он вытащил первого клиента в том же сеансе и потому, что возвращение было преобразовано взад и вперед, он не может распознать это как тот же объект.
Ты прав.Спящий режим не может.Чтобы исправить это, рассмотрите возможность реализации Equals и Hashcode.Я думаю, что повторное присоединение может сработать только в том случае, если вы не загрузили объект в этом сеансе.