2011-09-28 65 views
4

可愛的equals和hashCode,所有的理論是herehere使用自動生成的hibenate實體對象的ID在equals和hashCode方法

我已用等號內的自動生成的ID的決定()和hashcode()在我的一些休眠實體/域對象。

然而,一些網站說,你永遠不應該這樣做,由於持續的對象到數據庫中的第一次的風險,而這是在被比較或使用哈希碼的過程。

我的觀點是,在大多數情況下使用,這是更不可能比被改變任何其他領域。

各個領域對象有生成的ID一旦被首先創建時,而幾乎所有其他領域具有在正常的業務流程,以改變(甚至是唯一的用戶名可以改變...)的機會。

而在我的許多域對象中,唯一的id幾乎是唯一適合的字段需要考慮(Person,Address,Pet,... Customer等等等等)?合併字段是個好主意,但從來沒有使用自動生成的ID,我認爲,沒有好的建議。

我失去了什麼東西?

回答

3

你應該在Hibernate社區維基閱讀Equals and HashCode

不使用數據庫標識符equals和暗示hashCode的主要原因是用於處理已存儲但未保留的實體。在持久化之前,除非您明確地處理該情況,否則所有實例都將是equal

如果你知道你不會是在這種情況下,你要確保它是有據可查的,你很可能確定。您可以隨時更改實施。

0

我穿過等於因爲我已經把事實 與自動識別代問題就來了我一旦創建基於新用戶輸入的對象,就將它們設置爲Set。 所以我沒有明確地比較它們或者什麼,我只是把它們放入一個組。 在這一點上它已經失敗,因爲Set依靠的equals()/ hashCode()方法(這 又是基於對象ID,因爲我沒有其他的選擇)。

然後我改變了它實際產生和分配的ID我自己,這是更好的解決方案。

請閱讀這篇文章,它正好說明這個問題: dont-let-hibernate-steal-your-identity

1

不,我不認爲你錯過了任何基本的東西。將數據庫ID用於equals和hashCode的問題的「根本原因」是Hibernate生成的ID存儲在可變字段中,並且當Hibernate分配ID時,該字段的值會發生變化。 Equals和hashCode應該基於不可變狀態,如Odersky/Spoon/Venners article關於編寫equals/hashCode方法中的「陷阱#3」所述。這意味着,除了別的以外,您無法將實例添加到Set或將其與另一個實例進行比較,直到該實例持久存在,此時hashCode已修復。

您可能會遺漏的唯一情況是,您需要跟蹤ID的分配時間,這很棘手,因爲它是由Hibernate自動完成的。當然,你可能永遠不會調用setId(someNewId),但是你可能發出一個觸發會話刷新的查詢,並且與該查詢無關的一大堆瞬態實體突然將其ID從null更改爲非null。

對於equals和hashCode使用業務密鑰通常是Hibernate社區推薦的,但是這種方法也會遭受同樣的mutable-until-initialized問題。如果你的實體是一個由Hibernate急切加載的持久集的成員,那麼它可以在它的字段被初始化之前被添加到集合中,所以基於這些字段的hashCode也不起作用。參見Hibernate bug report討論業務密鑰相等的問題。

James Brundege recommends在應用程序代碼中分配ID以避免此問題。蘭斯阿勞斯有一個similar approach使用分配ID的對象工廠。

如果您確實想要爲equals和hashCode使用自動生成的ID,請考慮在您的equals和hashCode實現中使用Assert.notNull(id)來檢測編碼錯誤。

另請參閱另一個stackoverflow question與許多不同的方法討論。

相關問題