集合中的 Grails 域类

发布于 2024-11-14 11:12:33 字数 972 浏览 8 评论 0原文

集合中使用域对象或作为地图中的键是一种不好的做法吗?

过去我做过很多这样的事情

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

但是我注意到当 findAllByAuthorLike 可能返回 Hibernate 代理对象列表 com.me.Book_$$_javassist_128< 时,我经常遇到问题/code> 但 findByTitleLike 将返回正确的 com.me.Book 对象。这会导致集合中出现重复,因为真实对象和代理被认为相等。

我发现在使用这样的域对象集时需要非常小心,而且我感觉这可能是我一开始就不应该做的事情。

另一种选择当然是使用 id 的集合/映射,但它使我的代码变得冗长并且容易产生误解

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

@Burt:我认为 Grails 域类已经这样做了,至少这样等于/比较是在类/id 上完成的,而不是在对象实例上完成的。您是指休眠代理的特殊比较器吗?

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

Is it a bad practice to use domain objects in Sets or as keys in Maps?

In the past I've done things like this a lot

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

However I have noticed that I often encounter problems when findAllByAuthorLike might return a list of Hibernate Proxy objects com.me.Book_$$_javassist_128 but findByTitleLike will return a proper com.me.Book object. This causes duplicates in the set because the real object and the proxy are considered not equal.

I find I need to be extremely careful when using Sets of domain objects like this, and I get the feeling it might be something I should not be doing in the first place.

The alternative is of course to use a set/map of id's, but it makes my code verbose and prone to misunderstanding

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

@Burt: I thought Grails domain classes already did this, at least so that equals/compare was done on class/id's rather than the object instance. Do you mean a special comparator for hibernate proxies?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

十年不长 2024-11-21 11:12:33

这根本不是坏习惯,但就像在非 Grails 应用程序中一样,如果您要将它们放入基于哈希的集合中,则应该覆盖 equalshashCode (< code>HashSet、HashMap 等),如果您打算的话,还可以实现 Comparable (这意味着 compareTo 方法)使用TreeSet/TreeMap/等。

It's not bad practice at all, but just like in a non-Grails application you should override equals and hashCode if you'll be putting them in hash-based collections (HashSet, HashMap, etc.) and also implement Comparable (which implies a compareTo method) if you're going to use TreeSet/TreeMap/etc.

总攻大人 2024-11-21 11:12:33

在 Hibernate 支持的情况下正确实现 equals() 和 hashcode() 绝非易事。 Java 集合要求对象的哈希码和 equals() 的行为不会改变,但是当对象是新创建的对象时,其 id 可能会发生变化,并且其他字段可能会由于各种原因而发生变化。有时您有一个可以使用的良好的、不可更改的企业 ID,但通常情况并非如此。显然,默认的 Java 行为也不适合 Hibernate 情况。

我见过的最佳解决方案如下所述: http://onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html?page=2

解决方案描述的是:对象一创建就初始化id。不要等待 Hibernate 分配 id。配置 Hibernate 使用版本来确定它是否是新对象。这样,id 就不可更改,并且可以安全地用于 hashcode() 和 equals()。

Proper implementation of equals() and hashcode() in a Hibernate-backed situation is far from trivial. Java Collections require that hashcodes of objects and behaviour of equals() don't change, but the id of an object can change when it's a newly created object, and other fields can change for a wide variety of reasons. Sometimes you have a good unchangeable business id that you can use, but quite often that's not the case. And obviously default Java behaviour is also not suitable in a Hibernate situation.

The best solution I've seen is described here: http://onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html?page=2

The solution it describes is: initialize the id as soon as the object is created. Don't wait for Hibernate to assign an id. Configure Hibernate to use version to determine whether it's a new object. This way, id in unchangeable, and can be safely used for hashcode() and equals().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文