[英]Should @Transient property be used in equals/hashCode/toString?
我有JPA實體,其中一些屬性使用@Transient
注釋。
我應該在equals/hashCode/toString
方法中使用這些屬性嗎?
我的第一個想法是不,但我不知道為什么。
toString()
情況不同,你可以用toString()
做任何你想要的事情,所以我只會覆蓋equals()
(和hashCode()
)。
首先,規則: 如果要將對象存儲在List
, Map
或Set
,則需要實現equals
和hashCode
,以便它們遵守文檔中指定的標准合同 。
現在,如何實現equals()
和hashCode()
? 一個“自然”的想法是使用映射為Id
的屬性作為equals()
:
public class User {
...
public boolean equals(Object other) {
if (this==other) return true;
if (id==null) return false;
if ( !(other instanceof User) ) return false;
final User that = (User) other;
return this.id.equals( that.getId() );
}
public int hashCode() {
return id==null ? System.identityHashCode(this) : id.hashCode();
}
}
不幸的是,這個解決方案有一個主要問題 :當使用生成的標識符時,在實體變為持久化之前不會分配值,因此如果在保存之前將一個瞬態實體添加到Set
,則其哈希代碼將在Set
更改打破了Set
的合同。
因此,推薦的方法是使用屬於業務鍵的屬性,即對於具有相同數據庫標識的每個實例唯一的屬性組合。 例如,對於User類,這可以是用戶名:
public class User {
...
public boolean equals(Object other) {
if (this==other) return true;
if ( !(other instanceof User) ) return false;
final User that = (User) other;
return this.username.equals( that.getUsername() );
}
public int hashCode() {
return username.hashCode();
}
}
Hibernate參考文檔總結如下:
“ 永遠不要使用數據庫標識符來實現相等性;使用業務鍵,唯一的,通常是不可變的屬性的組合 。如果瞬態對象是持久的,數據庫標識符將會改變。如果瞬態實例(通常與分離的實例一起)是保存在
Set
,更改hashcode
會破壞Set
的約定。業務鍵的屬性不必像數據庫主鍵一樣穩定,只要對象在同一個Set中,就必須保證穩定性。 - 12.1.3。 考慮對象身份“ 建議您使用Business鍵相等來實現
equals()
和hashCode()
。業務鍵相等性意味着equals()
方法僅比較構成業務鍵的屬性。它是一個用於標識我們的實例的鍵。現實世界(自然候選鍵)“ - 4.3。 實現equals()和hashCode()
那么,回到最初的問題:
@Transient
屬性很可能不屬於這樣一個鍵。 List
, Map
, Set
之前獲取指定的值。 異常可能來自於讓它是transient
,同時你提供writeObject()
和readObject()
處理它。
我所知道的@Transient
和transient
的兩個典型用法是將它們用於無法序列化/持久化的東西(例如遠程資源句柄 )或可以從其他人重建的計算屬性。
對於計算數據 ,在等式關系( equals/hashCode
)中使用它們是沒有意義的,因為它將是多余的。 該值是從已在相等中使用的其他值計算出來的。 然而,在toString
打印它們仍然是有意義的(例如,基本價格和比率用於計算實際價格)。
對於不可序列化/可持久化的數據 ,它取決於。 我可以想象一個不可序列化的資源的句柄,但你仍然可以比較句柄所代表的資源名稱。 對於toString
,也許打印句柄資源名稱很有用。
這是我的2美分,但如果你解釋你對@Transient
的特殊用法,有人可以提供更好的建議。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.