Доменные классы Grails в наборах - PullRequest
7 голосов
/ 09 июня 2011

Разве это плохая практика - использовать объекты домена в Устанавливает или в качестве ключей в Картах?

В прошлом я много делал подобные вещи

Set<Book> someBooks = [] as Set
someBooks.addAll (Book.findAllByAuthorLike('%hofstadter%'))
someBooks.add (Book.findByTitleLike ('%eternal%'))

Однако я заметил, что часто сталкиваюсь с проблемами, когда findAllByAuthorLike может возвращать список объектов Hibernate Proxy com.me.Book_$$_javassist_128, но findByTitleLike возвращает правильный com.me.Book объект.Это вызывает дубликаты в наборе, потому что реальный объект и прокси считаются не равными.

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

Альтернативой, конечно, является использование набора / карты идентификаторов, но это делает мой код многословным и склонным к недоразумениям

Set<Integer> someBooks = [] as Set // a set of id's for books    

@ Burt: Я думал, что доменные классы Grails уже сделали это, по крайней мере, чтобы сравнение / сравнение было выполнено для классов / идентификаторов, а не для экземпляра объекта.Вы имеете в виду специальный компаратор для спящих прокси?

return (this.class == obj.class && this.id == obj.id) || 
       (obj.class  == someHibernateProxy && this.id == obj.id)

Ответы [ 2 ]

9 голосов
/ 09 июня 2011

Это совсем не плохая практика, но, как и в приложении без Grails, вы должны переопределить equals и hashCode, если будете помещать их в коллекции на основе хеша (HashSet, HashMap,и т. д.), а также реализовать Comparable (что подразумевает compareTo метод), если вы собираетесь использовать TreeSet / TreeMap / и т. д.

2 голосов
/ 24 августа 2011

Правильная реализация equals () и hashcode () в ситуации с поддержкой Hibernate далеко не тривиальна. Коллекции Java требуют, чтобы хеш-коды объектов и поведение equals () не менялись, но идентификатор объекта может изменяться, когда он является вновь созданным объектом, а другие поля могут изменяться по целому ряду причин. Иногда у вас есть хороший неизменяемый бизнес-идентификатор, который вы можете использовать, но довольно часто это не так. И, очевидно, поведение Java по умолчанию также не подходит в ситуации гибернации.

Лучшее решение, которое я видел, описано здесь: http://onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html?page=2

Решение, которое оно описывает: инициализировать идентификатор, как только объект будет создан. Не ждите, пока Hibernate назначит идентификатор. Настройте Hibernate для использования версии, чтобы определить, является ли это новым объектом. Таким образом, id в неизменяемом и может безопасно использоваться для hashcode () и equals ().

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