Hangi durumda JPA @JoinTable ek açıklamasını kullanırsınız?


Yanıtlar:


351

EDIT 2017-04-29 : Bazı yorumcular tarafından işaret edildiği gibi, JoinTableörnek mappedByek açıklama özelliğine ihtiyaç duymaz . Aslında, Hibernate'in son sürümleri aşağıdaki hatayı yazarak başlatılmayı reddeder:

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

Şu adda bir varlığınız olduğunu varsayalım: Project ve başka bir varlığınız olduğunu Taskve her projenin birçok görevi olabileceğini .

Bu senaryo için veritabanı şemasını iki şekilde tasarlayabilirsiniz.

İlk çözüm, adlı bir tablo Projectve adlı başka bir tablo oluşturmak ve Taskşu görev tablosuna bir yabancı anahtar sütunu eklemektir project_id:

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

Bu şekilde, görev tablosundaki her satır için projeyi belirlemek mümkün olacaktır. Bu yaklaşımı kullanırsanız, varlık sınıflarınızda bir birleştirme tablosuna ihtiyacınız olmaz:

@Entity
public class Project {

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

}

@Entity
public class Task {

   @ManyToOne
   private Project project;

}

Diğer çözüm, örneğin üçüncü bir tablo kullanmak Project_Tasksve bu tablodaki projeler ve görevler arasındaki ilişkiyi saklamaktır:

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

Project_TasksTablo "Üyelik Tablosu" denir. Bu ikinci çözümü JPA'da uygulamak için aşağıdaki çözümü kullanmanız gerekir:@JoinTable ek açıklamayı . Örneğin, bire bir çok yönlü bir birliktelik uygulamak için varlıkları şöyle tanımlayabiliriz:

Project varlık:

@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 varlık:

@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;
    }

}

Bu, aşağıdaki veritabanı yapısını oluşturur:

ER Şeması 1

@JoinTableEk açıklama da katılmak tablonun çeşitli yönlerini özelleştirmenizi sağlar. Örneğin, tasksmülke şu şekilde ek açıklama eklemiş olsaydık :

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

Ortaya çıkan veritabanı:

ER Şeması 2

Son olarak, çoktan çoğa ilişkilendirme için bir şema oluşturmak istiyorsanız, birleştirme tablosu kullanmak tek çözümdür.


1
ilk yaklaşımı kullanarak birleştirme ve çalışmadan önce Projemi görevlerim ve her bir Görev üst Proje ile doldurdum ama tüm girişlerim görevlerimin sayısına göre çoğaltılır. İki görevi olan bir proje veritabanımda iki kez kaydedilir. Neden ?
MaikoID

GÜNCELLEME Veritabanımda yinelenen girişler yok, hazırda bekletme sol dış birleştirme ile seçiyor ve neden bilmiyorum ..
MaikoID

2
@JoinTable/@JoinColumnAynı alana açıklama eklenebilir olduğuna inanıyorum mappedBy. Doğru örnek tutulması gerekir, böylece mappedByin Projectve hareket @JoinColumniçin Task.project (veya tam tersi ya da)
Adrian Şum

2
Güzel! Ama başka bir sorum var: tablo katılırsanız Project_Tasksihtiyacı nameiçinde Tasküç sütun haline gelir, sıra: project_id, task_id, task_name, nasıl bunu başarmak için?
macemers

5
Bu hatayı önlemek için ikinci kullanım örneğinizle eşleştirmemelisinizCaused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn:
karthik m

14

@JoinTableBir Varlığın farklı ebeveynlerle çeşitli ebeveyn / çocuk ilişkilerinde çocuk olabileceği durumlarda da kullanmak daha temizdir . Behrang örneğini takip etmek için, bir görevin Proje, Kişi, Departman, Çalışma ve Sürecin çocuğu olabileceğini hayal edin.

taskTablonun 5 nullableyabancı anahtar alanı olmalı mı ? Bence değil...


14

ManyToMany ilişkilendirmesini eşlemek için tek çözümdür: ilişkilendirmeyi eşlemek için iki varlık tablosu arasında bir birleştirme tablosuna ihtiyacınız vardır.

Ayrıca, birçok tarafın tablosuna yabancı bir anahtar eklemek istemediğinizde OneToMany (genellikle tek yönlü) dernekler için kullanılır ve böylece onu bir taraftan bağımsız tutar.

Açıklamalar ve örnekler için hazırda bekletme belgesinde @JoinTable öğesini arayın .


4

Çoktan çoğa ilişkiyi ele almanızı sağlar. Misal:

Table 1: post

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

Table 2: user

user has the following columns:

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

Birleştirme Tablosu aşağıdakileri kullanarak bir eşleme oluşturmanıza olanak tanır:

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

bir tablo oluşturur:

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

1
Soru: Bu ek tablo zaten varsa? JoinTable mevcut olanın üzerine yazmaz, değil mi?
TheWandererr

@TheWandererr sorunuzun cevabını buldunuz mu? Zaten bir katılma masam var
17:50

Benim durumumda, sahip olan yan tabloda yedekli bir sütun oluşturuyor. örneğin. POST içinde POST_ID. Neden olduğunu önerebilir misiniz?
SPS

0

@ManyToMany dernekler

Çoğu zaman, @JoinTableçoktan çoğa bir tablo ilişkisinin eşlenmesini belirtmek için ek açıklama kullanmanız gerekir :

  • bağlantı tablosunun adı ve
  • iki Yabancı Anahtar sütunu

Yani, aşağıdaki veritabanı tablolarına sahip olduğunuzu varsayarsak:

Çoktan çoğa tablo ilişkisi

Gelen Postvarlık, böyle bu ilişkiyi, harita olacaktır:

@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<>();

@JoinTableEk açıklama yoluyla tablo adı belirtmek için kullanılır nameözniteliği, hem de yabancı anahtar sütununun olduğu referanslar posttablo (örneğin joinColumns) ve Yabancı anahtar sütun post_tagbağlantı tablosunun o referanslar Tagyoluyla varlık inverseJoinColumnsözelliğinde.

@ManyToManyEk açıklamanın basamaklı özniteliğinin olarak ayarlandığına dikkat edin PERSISTve MERGEyalnızca REMOVEDELETE deyiminin, tagbizim durumumuzda, post_tagkayda değil , diğer üst kayıt için yayınlanacağı için basamaklı kötü bir fikir olduğu için . Bu konu hakkında daha fazla bilgi için bu makaleye göz atın .

Tek yönlü @OneToManyilişkiler

Tek yönlü @OneToManydernekler,@JoinColumnEşleme bulunmayan bire çok değil, çoktan çoğa tablo ilişkileri gibi davranır.

Aşağıdaki varlık eşlemelerine sahip olduğunuzu varsayarsak:

@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
}

Hazırda Beklet, yukarıdaki varlık eşlemesi için aşağıdaki veritabanı şemasını alır:

Tek yönlü <code> @OneToMany </code> JPA ilişkilendirme veritabanı tabloları

Daha önce açıklandığı gibi, tek yönlü @OneToManyJPA eşlemesi çoktan çoğa bir ilişki gibi davranır.

Bağlantı tablosunu özelleştirmek için @JoinTableek açıklamayı da kullanabilirsiniz :

@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<>();

Ve şimdi, bağlantı tablosu çağrılacak post_comment_refve Yabancı Anahtar sütunları post_id, posttablo post_comment_idiçin ve post_commenttablo için olacak.

Tek yönlü @OneToManyilişkilendirmeler verimli değildir, bu nedenle iki yönlü @OneToManyilişkilendirmeleri veya yalnızca @ManyToOnetarafı kullanmaktan daha iyi olursunuz . Bu konu hakkında daha fazla bilgi için bu makaleye göz atın .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.