![](/img/trans.png)
[英]generating a bulletprooh hashCode for Hibernate composite key
[英]there is find without overidding equals and hashCode in hibernate composite primary key
我正在使用休眠 4.3.10。
當引用復合主鍵時,我的實體看起來像 next (從@Master Slave 得到答案后添加了 equals() 和 hashCode() ) :
@Entity
@Table(name="compositepk")
public class Car {
@EmbeddedId
private CarPK carPK;
private String name;
public CarPK getCarPK() {
return carPK;
}
public void setCarPK(CarPK carPK) {
this.carPK = carPK;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Embeddable
public static class CarPK implements Serializable{
private static final long serialVersionUID = -5202331188724915048L;
private int chassisNumber;
private int engineNumber;
public int getChassisNumber() {
return chassisNumber;
}
public void setChassisNumber(int chassisNumber) {
this.chassisNumber = chassisNumber;
}
public int getEngineNumber() {
return engineNumber;
}
public void setEngineNumber(int engineNumber) {
this.engineNumber = engineNumber;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof CarPK) {
CarPK car = (CarPK)obj;
if(this.getChassisNumber().intValue() == car.getChassisNumber().intValue() &&
this.getEngineNumber().intValue() == car.getEngineNumber().intValue()) {
return true;
} else {
return false;
}
}
return false;
}
@Override
public int hashCode() {
return this.chassisNumber.hashCode()+this.engineNumber.hashCode();
}
}
}
hibernate 文檔說我們必須在復合主鍵中實現 equals() 和 hashCode() 。
但是,我發現在 CarPK 中不覆蓋它們就沒有任何問題。 我可以比較汽車並將它們添加到 Set 並得到正確的結果。 例如,以下是比較代碼:
Car.CarPK pk = new Car.CarPK();
pk.setChassisNumber(3);
pk.setEngineNumber(2017);
Car c1 = (Car) session1.get(Car.class, pk);
Car c2 = (Car) session2.get(Car.class, pk);
if(c1.equals(c2)) {
System.out.println("==");
} else {
System.out.println("!=");
}
如果chassisNumber 和engineNumber 相同,則此代碼打印“!=”並打印“==”。
(修改上面的代碼后,在不同的會話中得到相同的結果,上面的代碼打印“!=”,為什么?不應該打印“==”,因為我已經實現了equals()和hashCode()? )
那么當我沒有在 CarPK 中實現 equals() 和 hashCode() 時,任何人都可以告訴我問題嗎?
提前致謝!
我花了一些時間才弄清楚,但您還必須覆蓋Car
equals
和hashCode
@Override
public boolean equals(Object obj) {
if(obj instanceof Car) {
Car that = (Car) obj;
return this.carPK.equals(that.carPK);
}
return false;
}
@Override
public int hashCode() {
return this.carPK.hashCode();
}
順便說一句,您的hashCode
在CarPK
的實現是危險的(並且是錯誤的,因為它無法編譯)。 生成 2 CarPK
具有相同hashCode
但不equals
CarPK
太容易了
Car.CarPK pk1 = new Car.CarPK();
pk1.setChassisNumber(3);
pk1.setEngineNumber(2017);
Car.CarPK pk2 = new Car.CarPK();
pk2.setChassisNumber(1500);
pk2.setEngineNumber(520);
System.out.println(pk1.hashCode()); //prints 2020
System.out.println(pk2.hashCode()); //prints 2020
//Same hashCode, should be equal, just checking...
System.out.println(pk1.equals(pk2)); //prints false !
我推薦你這個實現,它更難產生碰撞
@Override
public int hashCode() {
return Objects.hash(chassisNumber, engineNumber);
}
您的測試有效,因為您處於相同的會話/持久性上下文中。 假設您嘗試在兩個不同的持久上下文中加載實體(再次使用相同的值),您將意識到它是一個不同的 java 對象。
這就是為什么您必須實現業務鍵均衡,因此hashCode
和equals
將告訴 hibernate 如何推理對象相等,並且無論對象的狀態如何(瞬態、附加、分離)都應該保持不變。 基於上述,id 屬性不是哈希/等於合約的一部分,因為它的值取決於狀態
從文檔
Hibernate 使用 Hibernate 會話來管理這種唯一性。 當您使用 new() 創建一個對象,然后將其保存到會話中時,Hibernate 現在知道每當您查詢一個對象並找到該特定對象時,Hibernate 都應該返回該對象的實例。 而 Hibernate 會做到這一點。 但是,一旦您關閉 Hibernate 會話,所有賭注都將取消。 如果你一直持有一個在你現在關閉的 Hibernate 會話中創建或加載的對象,Hibernate 無法知道這些對象。 因此,如果您打開另一個會話並查詢“相同”對象,Hibernate 將返回一個新實例。 因此,如果您在會話之間保留對象集合,您將開始遇到奇怪的行為(主要是集合中的重復對象)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.