NHibernate, DTO и NonUniqueObjectException - PullRequest
2 голосов
/ 14 мая 2009

Мы используем шаблон DTO для маршалинга наших доменных объектов из сервисного уровня в наш репозиторий, а затем в базу данных через NHibernate.

Я столкнулся с проблемой, из-за которой я вытаскиваю DTO из репозитория (например, CustomerDTO), а затем преобразовываю его в объект домена (Customer) на своем уровне обслуживания. Затем я пытаюсь сохранить новый объект обратно (например, SalesOrder), который содержит тот же объект Customer. Это, в свою очередь, преобразуется в SalesOrderDTO (и CustomerDTO) для отправки в репозиторий.

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

Я застрял здесь или есть способ обойти это?

Спасибо

Джеймс

Ответы [ 4 ]

2 голосов
/ 03 июня 2009

Как уже отмечали другие, реализация Equals и GetHashCode - это шаг в правильном направлении. Также обратите внимание на поддержку NHibernate для идиомы «присоединить» OR / M.

В вашем распоряжении также опция nosetter.camelcase: http://davybrion.com/blog/2009/03/entities-required-properties-and-properties-that-shouldnt-be-modified/

Кроме того, я хотел бы призвать вас не отговаривать от отсутствия информации в Интернете. Это не значит, что ты сумасшедший или делаешь что-то не так. Это просто означает, что вы работаете в крайнем случае. К сожалению, крупнейшими потребителями таких библиотек, как NHibernate, являются небольшие собственные и / или веб-приложения, в которых есть свобода использовать все ваши постоянные потребности в одной базе данных. В действительности есть много исключений из этого правила.

Например, в настоящее время я работаю над коммерческим настольным приложением, в котором один из моих доменных объектов имеет свои данные, распределенные между базой данных SQL CE и файлами изображений на диске. К сожалению, NHibernate может помочь мне только с сохранением SQL CE. Я вынужден использовать своего рода «двойное сопоставление» (см. «Шаблоны архитектуры корпоративных приложений» Мартина Фаулера * ), чтобы сопоставить мою модель домена через уровень хранилища, который знает, какие данные отправляются в NHibernate, а что на диск .

Это случается. Это реальная необходимость. Иногда очевидный недостаток инструмента указывает на то, что вы используете плохой подход. Но иногда правда в том, что вы действительно находитесь в предельном случае, и вам нужно создать некоторые из этих шаблонов для себя, чтобы это сделать.

2 голосов
/ 14 мая 2009

Это действительно о том, как работает сессия NHibernate. Поэтому, если вы в течение сеанса извлекаете экземпляр вашего CustomerDTO, а затем через некоторое время вы должны получить тот же CustomerDTO (скажем, по первичному ключу) - вы фактически получите ссылку на тот же объект, что и в первом поиске.

То, что вы делаете, это то, что вы либо объединяете объекты, вызывая session.Merge, либо запрашиваете сеанс для объекта, вызывая session.Get (primaryKey) обновляет и очищает сеанс.

Однако, как предполагает Стив, - это обычно не то, что вы делаете - вы действительно хотите получить свой объект домена из хранилища данных и использовать DTO (если это необходимо) для передачи данных в пользовательский интерфейс, веб-сервис, что угодно ...

2 голосов
/ 14 мая 2009

Вы можете повторно присоединить объект к сеансу в NHibernate, используя Lock - например,

_session.Lock(myDetachedObject, NHibernate.LockMode.None);

, что может или не может помочь в зависимости от того, что именно здесь происходит. Напомним, что использование DTO с NHibernate - не самая распространенная практика, тот факт, что NHibernate (в основном) поддерживает постоянное невежество, означает, что DTO обычно не так широко используются, как с некоторыми другими платформами ORM.

1 голос
/ 14 мая 2009

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

Вы правы. Спящий режим не может. Рассмотрите реализацию Equals и Hashcode, чтобы это исправить. Я думаю, что повторное присоединение может работать, только если вы не загрузили объект в этом сеансе.

...