我应该如何覆盖具有复合主键的实体中的 equals/hashCode?

How should I override equals/hashCode in entities with composite primary keys?

我有一个 table,它有一个复合主键,包括它自己的和来自其他 table 的外键。

我决定不使用 @IdClass@EmbeddedId

class SomeEntity {

    @Id
    private String someId;

    @Id
    @ManyToOne(optional = false)
    @JoinColumn(name = ...)
    private Other other

    // other mappings here
}

Hibernate 会警告这些。

WARN 69752 ... : HHH000038: Composite-id class does not override equals(): ....Some
WARN 69752 ... : HHH000039: Composite-id class does not override hashCode(): ....Some

我如何(应该)实现这两个方法?

我可以(应该)只包含这两个字段吗?其他领域呢?

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Some that = (Some) o;
        return Objects.equals(someId, that.someId) &&
                Objects.equals(other, that.other);
    }

    @Override
    public int hashCode() {
        return Objects.hash(someId, other);
    }

I decided not to use an @IdClass nor @EmbeddedId.

不得不说这个决定有两个缺点:

  1. JPA 规范不允许这种方法,因此它是休眠特定的解决方案。 (参见 this
  2. 实体实例和实际标识符之间没有分离。要查询此实体,必须将实体本身的实例提供给持久性上下文。 (参见 this

想象一下,您有以下实体:

@Entity
@Table(name = "TST_FIRST_ENTITY_EHC")
public class FirstEntity implements Serializable 
{
   @Id
   @Column(name = "fst_id")
   private Long id;
   
   @NaturalId
   @Column(name = "fst_code")
   private String code;
   
   @Id
   @ManyToOne(optional = false)
   @JoinColumn(name = "fst_sec_id")
   private SecondEntity secondEntity;
   
   public FirstEntity()
   {
   }
   
   public FirstEntity(Long id, Long secId)
   {
      this.id = id;
      secondEntity = new SecondEntity();
      secondEntity.setId(secId);
   }
   // ...
}

要通过 PK 找到这个实体,你应该这样写:

FirstEntity item = session.find(FirstEntity.class, new FirstEntity(1L, 2L));

我呢,看着挺别扭的

至于您的主要问题,您可以使用任何一组字段来标识您的实体。 想象一下,对于上述实体,您具有以下 DDL SQL:

create table TST_FIRST_ENTITY_EHC
(
   fst_id bigint,
   fst_sec_id bigint,
   fst_code varchar(25),
   fst_value varchar(500),
   
   primary key (fst_id, fst_sec_id),
   unique(fst_code),
   foreign key (fst_sec_id) REFERENCES TST_SECOND_ENTITY_EHC(sec_id)
);

您可以根据 idsecondEntity.id 字段或 code 字段实现实体的 equalshashCode。基于 natural-id 或 business-key 的方法更可取,因为如果您使用数据库 id 生成,您无法在提交 JPA 事务之前知道实际的 id 值。 (参见 this)。