Какими свойствами должен обладать класс, чтобы быть сущностью (Entity) в Hibernate?

«Какими свойствами должен обладать класс, чтобы быть сущностью (Entity) в Hibernate?» — вопрос из категории Hibernate, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Требования к классу-сущности в Hibernate совпадают со спецификацией JPA и включают:

Обязательные условия:

  1. Аннотация @Entity.
  2. Наличие поля с @Id (первичный ключ).
  3. Пустой конструктор (доступ public или protected).
  4. Класс не должен быть объявлен как final.
  5. Методы-аксессоры (геттеры/сеттеры) для персистентных полей не должны быть final.

Рекомендации и best practices:

  • Поля обычно объявляются как private.
  • Реализуйте методы equals() и hashCode(), основанные на бизнес-ключе (уникальном наборе полей, кроме @Id), а не на сгенерированном ID, так как ID присваивается после сохранения.
  • Используйте аннотации для маппинга: @Table, @Column, @OneToMany, @ManyToOne и т.д.

Пример сущности с бизнес-ключом:

@Entity
@Table(name = "products")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    @Column(unique = true, nullable = false)
    private String sku; // Часть бизнес-ключа

    private String name;

    public Product() {}

    // equals и hashCode на основе sku (бизнес-ключ)
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Product product = (Product) o;
        return Objects.equals(sku, product.sku);
    }

    @Override
    public int hashCode() {
        return Objects.hash(sku);
    }
    // Геттеры и сеттеры...
}

Почему важен бизнес-ключ для equals/hashCode? Пока объект не сохранен в БД, его id равен null. Сравнение по id сломает контракт этих методов. Сравнение по неизменяемому уникальному полю (например, артикулу sku) решает эту проблему.