Hangi durumda JPA @JoinTable
ek açıklamasını kullanıyorsunuz?
Hangi durumda JPA @JoinTable
ek açıklamasını kullanıyorsunuz?
Yanıtlar:
EDIT 2017-04-29 : Bazı yorumcular tarafından işaret edildiği gibi, JoinTable
örnek mappedBy
ek 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 Task
ve her projenin birçok görevi olabileceğini .
Bu senaryo için veritabanı şemasını iki şekilde tasarlayabilirsiniz.
İlk çözüm, adlı bir tablo Project
ve 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_Tasks
ve 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_Tasks
Tablo "Ü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:
@JoinTable
Ek açıklama da katılmak tablonun çeşitli yönlerini özelleştirmenizi sağlar. Örneğin, tasks
mü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ı:
Son olarak, çoktan çoğa ilişkilendirme için bir şema oluşturmak istiyorsanız, birleştirme tablosu kullanmak tek çözümdür.
@JoinTable/@JoinColumn
Aynı alana açıklama eklenebilir olduğuna inanıyorum mappedBy
. Doğru örnek tutulması gerekir, böylece mappedBy
in Project
ve hareket @JoinColumn
için Task.project
(veya tam tersi ya da)
Project_Tasks
ihtiyacı name
içinde Task
üç sütun haline gelir, sıra: project_id
, task_id
, task_name
, nasıl bunu başarmak için?
Caused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn:
@JoinTable
Bir 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.
task
Tablonun 5 nullable
yabancı anahtar alanı olmalı mı ? Bence değil...
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 .
Ç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 |
|_________|_________|
| | |
|_________|_________|
@ManyToMany
derneklerÇoğu zaman, @JoinTable
çoktan çoğa bir tablo ilişkisinin eşlenmesini belirtmek için ek açıklama kullanmanız gerekir :
Yani, aşağıdaki veritabanı tablolarına sahip olduğunuzu varsayarsak:
Gelen Post
varlı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<>();
@JoinTable
Ek açıklama yoluyla tablo adı belirtmek için kullanılır name
özniteliği, hem de yabancı anahtar sütununun olduğu referanslar post
tablo (örneğin joinColumns
) ve Yabancı anahtar sütun post_tag
bağlantı tablosunun o referanslar Tag
yoluyla varlık inverseJoinColumns
özelliğinde.
@ManyToMany
Ek açıklamanın basamaklı özniteliğinin olarak ayarlandığına dikkat edinPERSIST
veMERGE
yalnızcaREMOVE
DELETE deyiminin,tag
bizim durumumuzda,post_tag
kayda 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 .
@OneToMany
ilişkilerTek yönlü @OneToMany
dernekler,@JoinColumn
Eş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:
Daha önce açıklandığı gibi, tek yönlü @OneToMany
JPA eşlemesi çoktan çoğa bir ilişki gibi davranır.
Bağlantı tablosunu özelleştirmek için @JoinTable
ek 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_ref
ve Yabancı Anahtar sütunları post_id
, post
tablo post_comment_id
için ve post_comment
tablo için olacak.
Tek yönlü
@OneToMany
ilişkilendirmeler verimli değildir, bu nedenle iki yönlü@OneToMany
ilişkilendirmeleri veya yalnızca@ManyToOne
tarafı kullanmaktan daha iyi olursunuz . Bu konu hakkında daha fazla bilgi için bu makaleye göz atın .