Какими свойствами должен обладать класс, чтобы его можно было отобразить на таблицу в БД с помощью JPA/Hibernate?

Ответ

Для маппинга класса на таблицу БД с помощью JPA/Hibernate класс должен быть сущностью (Entity). Основные шаги и свойства:

  1. Пометить класс аннотацией @Entity.
  2. Определить первичный ключ с помощью @Id. Часто используется @GeneratedValue для автоматической генерации ID.
  3. Сопоставить класс с таблицей (опционально, но рекомендуется) с помощью @Table(name = "table_name").
  4. Сопоставить поля со столбцами с помощью @Column. Без этой аннотации поле всё равно будет маппиться на столбец с тем же именем.
  5. Соблюсти требования JPA к Entity (пустой конструктор, не-final класс и методы).

Полный пример маппинга:

@Entity // 1. Объявляем сущность
@Table(name = "employees") // 3. Указываем имя таблицы
public class Employee {
    @Id // 2. Первичный ключ
    @GeneratedValue(strategy = GenerationType.IDENTITY) // Автоинкремент в БД
    private Long id;

    @Column(name = "full_name", length = 200, nullable = false) // 4. Маппинг поля
    private String name;

    @Column(unique = true) // Ограничение UNIQUE
    private String email;

    @Transient // Поле НЕ будет сохранено в БД
    private String temporaryCode;

    // 5. Обязательный конструктор
    public Employee() {}

    // Конструктор для удобства
    public Employee(String name, String email) {
        this.name = name;
        this.email = email;
    }
    // Геттеры и сеттеры...
}

Ключевые аннотации для связей между таблицами:

  • @OneToMany, @ManyToOne, @OneToOne, @ManyToMany — для отображения связей.
  • @JoinColumn — для указания столбца внешнего ключа.

Почему @Column не всегда обязателен? Hibernate по умолчанию маппит поле на столбец с тем же именем. Однако @Column необходим для задания дополнительных свойств: nullable, unique, length (для строк), precision/scale (для чисел).

Ответ 18+ 🔞

Давай разберём эту всю хрень с маппингом, а то я вижу, у некоторых глаза уже стеклянные, как у пойманной Муму перед утоплением.

Вот смотри, чтобы твой обычный, ни в чём не повинный Java-класс стал полноценной сущностью в базе данных, его надо правильно обрядить. Как наряжают покойника, только веселее.

Первое и главное — ты должен крикнуть на весь мир, что этот класс теперь сущность. Вешаешь на него аннотацию @Entity. Без этого — нихуя не работает, Hibernate на тебя даже смотреть не будет.

@Entity // 1. Всё, чувак, ты теперь не просто POJO, ты — Entity. Поздравляю, блядь.

Дальше — каждому уважающему себя объекту в базе нужен паспорт, уникальный идентификатор. Это @Id. А чтобы не париться с придумыванием чисел, вешаем @GeneratedValue. Стратегия IDENTITY — это типа "база, роди мне новый айдишник, когда я вставляю запись".

    @Id // 2. Это твой главный ключ, первичный, блядь. Без него — пиздец.
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

Теперь про таблицы. По умолчанию Hibernate создаст таблицу с именем класса. Но если ты не конченый мазохист и у тебя в базе таблицы называются не MySuperPuperEntity, а, допустим, users, то надо явно указать. Для этого @Table(name = "название_таблицы").

@Table(name = "employees") // 3. Чтоб не в `employee`, а именно в `employees`. Чисто для приличия.

Поля и колонки. Тут, в принципе, можно нихуя не делать. Hibernate сам догадается, что поле email надо положить в колонку email. Но если ты хочешь быть хитрожопым и задать ограничения (типа NOT NULL, длину строки или UNIQUE), то без @Column — никуда.

    @Column(name = "full_name", length = 200, nullable = false) // 4. Имя в колонке `full_name`, не больше 200 символов и НЕ NULL, ёпта!
    private String name;

    @Column(unique = true) // Ограничение UNIQUE. Два одинаковых email'а — и будет тебе конфликт, пиздец.
    private String email;

А бывают поля-призраки. Они есть в Java-объекте, но в базу их класть не надо. Например, какая-нибудь временная хуйня для вычислений. Для этого — @Transient. Словно его и нет.

    @Transient // Поле НЕ будет сохранено в БД. Как сон, как утренний туман.
    private String temporaryCode;

И да, не забудь про священный ритуал JPA — пустой конструктор. Без него Hibernate обосрётся с ошибкой, когда будет пытаться создать объект через рефлексию. Класс и методы не должны быть final. В общем, играй по правилам, пидрила.

    // 5. Обязательный пустой конструктор. Даже если он тебе не нужен. Сделал и забыл.
    public Employee() {}

А теперь смотри, как это всё вместе выглядит, этот шедевр маппинга:

@Entity
@Table(name = "employees")
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "full_name", length = 200, nullable = false)
    private String name;

    @Column(unique = true)
    private String email;

    @Transient
    private String temporaryCode;

    public Employee() {}

    public Employee(String name, String email) {
        this.name = name;
        this.email = email;
    }
    // Геттеры и сеттеры... (без них тоже, в принципе, можно, но некрасиво)
}

Ну и на последок, про связи. Это когда одни сущности ссылаются на другие. Тут тебе в помощь целый арсенал: @OneToMany, @ManyToOne, @OneToOne, @ManyToMany. А чтобы указать, в какой колонке лежит внешний ключ — @JoinColumn. Но это уже, как говорится, совсем другая история, ебать её в сраку. Для первого раза и этого овердохуища хватит.