Как мне переопределить equals / hashCode в сущностях с составными первичными ключами? - PullRequest
3 голосов
/ 19 июня 2020

У меня есть таблица с составными первичными ключами, включая его собственный и FK из другой таблицы.

Я решил не использовать ни @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);
    }

1 Ответ

1 голос
/ 21 июня 2020

Я решил не использовать ни @IdClass, ни @EmbeddedId.

Я должен сказать, что это решение имеет два недостатка:

  1. Это подход не разрешен спецификацией JPA, поэтому это решение для спящего режима c. (См. 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)
);

Вы можете реализовать equals и hashCode своей сущности на основе полей id, secondEntity.id или на основе поля code. Подход, основанный на естественном идентификаторе или бизнес-ключе, является предпочтительным, потому что, если вы используете генерацию идентификатора базы данных, вы не можете знать фактические значения идентификатора до того, как транзакция JPA будет зафиксирована. (См. это ).

...