У якому випадку ви використовуєте анотацію JPA @JoinTable?


Відповіді:


351

EDIT 2017-04-29 : Як вказували деякі коментатори, JoinTableприкладу mappedByанотація анотації не потрібен . Насправді останні версії Hibernate відмовляються запускати, друкуючи таку помилку:

org.hibernate.AnnotationException: 
   Associations marked as mappedBy must not define database mappings 
   like @JoinTable or @JoinColumn

Давайте зробимо вигляд, що у вас є ім’я Projectта ім’я, іменоване інше, Taskі кожен проект може мати багато завдань.

Можна створити схему бази даних для цього сценарію двома способами.

Перше рішення - створити таблицю з ім'ям Projectта іншу таблицю з ім'ям Taskта додати стовпчик із зовнішнім ключем до таблиці завдань з назвою project_id:

Project      Task
-------      ----
id           id
name         name
             project_id

Таким чином, можна буде визначити проект для кожного рядка в таблиці завдань. Якщо ви використовуєте цей підхід, у класах вашої особи вам не знадобиться таблиця приєднання:

@Entity
public class Project {

   @OneToMany(mappedBy = "project")
   private Collection<Task> tasks;

}

@Entity
public class Task {

   @ManyToOne
   private Project project;

}

Іншим рішенням є використання третьої таблиці, наприклад Project_Tasks, і збереження взаємозв'язку між проектами та завданнями в цій таблиці:

Project      Task      Project_Tasks
-------      ----      -------------
id           id        project_id
name         name      task_id

Project_TasksТаблиця називається «Join Table». Для реалізації цього другого рішення в JPA потрібно використовувати @JoinTableанотацію. Наприклад, для реалізації однонаправленої асоціації один на багато, ми можемо визначити наші сутності як такі:

Project суб'єкт:

@Entity
public class Project {

    @Id
    @GeneratedValue
    private Long pid;

    private String name;

    @JoinTable
    @OneToMany
    private List<Task> tasks;

    public Long getPid() {
        return pid;
    }

    public void setPid(Long pid) {
        this.pid = pid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Task> getTasks() {
        return tasks;
    }

    public void setTasks(List<Task> tasks) {
        this.tasks = tasks;
    }
}

Task суб'єкт:

@Entity
public class Task {

    @Id
    @GeneratedValue
    private Long tid;

    private String name;

    public Long getTid() {
        return tid;
    }

    public void setTid(Long tid) {
        this.tid = tid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Це створить таку структуру бази даних:

Діаграма 1

@JoinTableАнотацій також дозволяє налаштовувати різні аспекти приєднання таблиці. Наприклад, якби ми помітили такі tasksвластивості:

@JoinTable(
        name = "MY_JT",
        joinColumns = @JoinColumn(
                name = "PROJ_ID",
                referencedColumnName = "PID"
        ),
        inverseJoinColumns = @JoinColumn(
                name = "TASK_ID",
                referencedColumnName = "TID"
        )
)
@OneToMany
private List<Task> tasks;

Отримана база даних стала б:

Діаграма 2

Нарешті, якщо ви хочете створити схему для асоціації багатьох до багатьох, використання таблиці приєднання є єдиним доступним рішенням.


1
використовуючи перший підхід, я мій проект заповнював своїми завданнями, а кожне завдання, заповнене батьківським проектом, до об'єднання та роботи, але всі мої записи дублюються залежно від кількості моїх завдань. Проект з двома завданнями двічі зберігається в моїй базі даних. Чому?
MaikoID

ОНОВЛЕННЯ У моїй базі даних про копії немає, сплячий режим
вибирається

2
Я вважаю, що @JoinTable/@JoinColumnможна помітити на тому ж полі з mappedBy. Таким чином, правильний приклад повинен бути зберігаючи mappedByін Project, і перемістити @JoinColumnдо Task.project (або навпаки)
Адріан Shum

2
Приємно! Але у мене є ще один питання: якщо приєднатися до таблиці Project_Tasksпотребує nameв Taskа, яка стає три колонки: project_id, task_id, task_name, як домогтися цього?
макемери

5
Я думаю, вам не слід було б відображати карту на вашому другому прикладі використання, щоб запобігти цій помилціCaused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn:
karthik m

14

Це також чистіше використовувати, @JoinTableколи суб'єктом господарювання може бути дитина у кількох стосунках батьків / дитини з різними типами батьків. Щоб продовжити приклад Бехранга, уявіть, що завдання може бути дочірнім проекту, персоналу, відділу, навчання та процесу.

Чи має taskтаблиця містити 5 nullableзовнішніх ключових полів? Я думаю, що не...


14

Це єдине рішення для створення об'єднання ManyToMany: вам потрібна таблиця приєднання між двома таблицями сутностей для відображення асоціації.

Він також використовується для OneToMany (зазвичай однонаправлених) асоціацій, коли ви не хочете додавати іноземний ключ у таблицю багатьох сторін і таким чином зберігати його незалежно від однієї сторони.

Шукайте @JoinTable у сплячій документації для пояснень та прикладів.


4

Це дозволяє вам керувати відносинами «Багато на багатьох». Приклад:

Table 1: post

post has following columns
____________________
|  ID     |  DATE   |
|_________|_________|
|         |         |
|_________|_________|

Table 2: user

user has the following columns:

____________________
|     ID  |NAME     |
|_________|_________|
|         |         |
|_________|_________|

Таблиця приєднання дозволяє створювати відображення за допомогою:

@JoinTable(
  name="USER_POST",
  joinColumns=@JoinColumn(name="USER_ID", referencedColumnName="ID"),
  inverseJoinColumns=@JoinColumn(name="POST_ID", referencedColumnName="ID"))

створимо таблицю:

____________________
|  USER_ID| POST_ID |
|_________|_________|
|         |         |
|_________|_________|

1
Питання: а що, якщо у мене вже є ця додаткова таблиця? Ніяк JoinTable не замінить існуючий вірно?
TheWandererr

@TheWandererr Ви дізналися відповідь на своє запитання? У мене вже є таблиця приєднання
Asgs

У моєму випадку це створення зайвого стовпчика у власній бічній таблиці. напр. POST_ID в POST. Чи можете ви підказати, чому це відбувається?
SPS

0

@ManyToMany асоціації

Найчастіше вам потрібно буде використовувати @JoinTableанотацію, щоб вказати відображення співвідношення таблиці «багато-багато»:

  • назва таблиці посилань та
  • два стовпці Іноземного ключа

Отже, якщо у вас є такі таблиці баз даних:

Столові стосунки «багато до багатьох»

В Postсутності, ви б зіставити ці відносини, як це:

@ManyToMany(cascade = {
    CascadeType.PERSIST,
    CascadeType.MERGE
})
@JoinTable(
    name = "post_tag",
    joinColumns = @JoinColumn(name = "post_id"),
    inverseJoinColumns = @JoinColumn(name = "tag_id")
)
private List<Tag> tags = new ArrayList<>();

@JoinTableАнотацій використовується для вказівки імені таблиці з допомогою nameатрибута, а також стовпці Зовнішнього ключа, посилається на postтаблиці (наприклад, joinColumns) і стовпець зовнішнього ключа в post_tagтаблиці посилань , що посилається на Tagоб'єктному через inverseJoinColumnsатрибут.

Зверніть увагу, що атрибут каскаду @ManyToManyанотації встановлений PERSISTі MERGEлише тому, що каскадування REMOVEє поганою ідеєю, оскільки ми DELETE-виписка буде видана для іншої батьківської записи, tagв нашому випадку - не до post_tagзапису. Більш детально про цю тему перегляньте цю статтю .

Односпрямовані @OneToManyасоціації

Односпрямовані @OneToManyасоціації, яким не вистачає @JoinColumnвідображення, поводяться як стільникові відносини «багато-багато», а не «один-багато».

Отже, якщо у вас є такі відображення сутності:

@Entity(name = "Post")
@Table(name = "post")
public class Post {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    @OneToMany(
        cascade = CascadeType.ALL,
        orphanRemoval = true
    )
    private List<PostComment> comments = new ArrayList<>();

    //Constructors, getters and setters removed for brevity
}

@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {

    @Id
    @GeneratedValue
    private Long id;

    private String review;

    //Constructors, getters and setters removed for brevity
}

Hibernate передбачає наступну схему бази даних для вищезгаданого відображення сутності:

Односпрямовані <code> @OneToMany </code> таблиці баз даних асоціацій JPA

Як уже було пояснено, односпрямоване @OneToManyвідображення JPA веде себе як асоціація "багато хто".

Щоб налаштувати таблицю посилань, ви також можете використовувати @JoinTableпримітку:

@OneToMany(
    cascade = CascadeType.ALL,
    orphanRemoval = true
)
@JoinTable(
    name = "post_comment_ref",
    joinColumns = @JoinColumn(name = "post_id"),
    inverseJoinColumns = @JoinColumn(name = "post_comment_id")
)
private List<PostComment> comments = new ArrayList<>();

І тепер таблиця посилань буде називатися, post_comment_refі стовпці "Зовнішній ключ" будуть post_idдля postтаблиці та post_comment_idдля post_commentтаблиці.

Односпрямовані @OneToManyасоціації не ефективні, тому вам краще скористатися двонаправленими @OneToManyасоціаціями або просто @ManyToOneстороною. Перегляньте цю статтю, щоб дізнатися більше про цю тему.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.