java - hibernate复合主键中存在find而不覆盖equals和hashCode

标签 java hibernate composite-primary-key

我使用的是 hibernate 4.3.10。

当引用复合主键时,我的实体看起来像下一个(从@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 相同,则打印“==”。

(修改上面的代码后,在不同的 session 中得到相同的结果,上面的代码打印“!=”,为什么?它不应该打印出“==”,因为我已经实现了 equals( )和 hashCode()?)

那么有人可以告诉我当我没有在 CarPK 中实现 equals() 和 hashCode() 时出现的问题吗?

提前致谢!

最佳答案

我花了一些时间才弄清楚,但您还必须重写 Car 中的 equalshashCode

@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();
}

顺便说一句,您在 CarPK 中的 hashCode 实现是危险的(并且是 false,因为它无法编译)。生成 2 个具有相同 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 - hibernate复合主键中存在find而不覆盖equals和hashCode,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35828119/

相关文章:

hibernate - 与LIKE的HQL查询出现问题

.net - Entity Framework 中的复合键在 uwp 中使用 sqlite

java - 如何使用人工智能开发光学字符识别器?

java - 将 JSON 反序列化为类实例

Java 夏令时和 hibernate

java - Hibernate:调用 List.contains 时不会调用 contains

java - Maven checkstyle 未在目标中触发

java - 抽象类中的 XmlRootElement 注释 - 可能吗?

sql-server-2005 - SQL Server 2005 中外键与复合主键的关系

python - 如何在 SQLAlchemy 中定义复合主键