Nesse caso, você usa a @JoinTable
anotação JPA ?
Nesse caso, você usa a @JoinTable
anotação JPA ?
Respostas:
EDIT 2017-04-29 : Como apontado por alguns dos comentaristas, o JoinTable
exemplo não precisa do mappedBy
atributo de anotação. De fato, as versões recentes do Hibernate se recusam a iniciar, imprimindo o seguinte erro:
org.hibernate.AnnotationException:
Associations marked as mappedBy must not define database mappings
like @JoinTable or @JoinColumn
Vamos fingir que você tem uma entidade chamada Project
e outra entidade chamadaTask
e cada projeto pode ter muitas tarefas.
Você pode projetar o esquema do banco de dados para este cenário de duas maneiras.
A primeira solução é criar uma tabela denominada Project
e outra tabela denominada Task
e adicionar uma coluna de chave estrangeira à tabela de tarefas denominada project_id
:
Project Task
------- ----
id id
name name
project_id
Dessa forma, será possível determinar o projeto para cada linha na tabela de tarefas. Se você usar essa abordagem, em suas classes de entidade, não precisará de uma tabela de junção:
@Entity
public class Project {
@OneToMany(mappedBy = "project")
private Collection<Task> tasks;
}
@Entity
public class Task {
@ManyToOne
private Project project;
}
A outra solução é usar uma terceira tabela, por exemplo Project_Tasks
, e armazenar o relacionamento entre projetos e tarefas nessa tabela:
Project Task Project_Tasks
------- ---- -------------
id id project_id
name name task_id
A Project_Tasks
tabela é chamada "Tabela de junção". Para implementar esta segunda solução no JPA, você precisa usar a @JoinTable
anotação. Por exemplo, para implementar uma associação unidirecional um para muitos, podemos definir nossas entidades da seguinte forma:
Project
entidade:
@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
entidade:
@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;
}
}
Isso criará a seguinte estrutura de banco de dados:
A @JoinTable
anotação também permite personalizar vários aspectos da tabela de junção. Por exemplo, se tivéssemos anotado a tasks
propriedade assim:
@JoinTable(
name = "MY_JT",
joinColumns = @JoinColumn(
name = "PROJ_ID",
referencedColumnName = "PID"
),
inverseJoinColumns = @JoinColumn(
name = "TASK_ID",
referencedColumnName = "TID"
)
)
@OneToMany
private List<Task> tasks;
O banco de dados resultante teria se tornado:
Por fim, se você deseja criar um esquema para uma associação muitos-para-muitos, o uso de uma tabela de junção é a única solução disponível.
@JoinTable/@JoinColumn
pode ser anotado no mesmo campo com mappedBy
. Assim, o exemplo correcta deve ser manter o mappedBy
na Project
, e mover o @JoinColumn
para Task.project
(ou vice-versa)
Project_Tasks
precisa do name
de Task
bem, que se torna três colunas: project_id
, task_id
, task_name
, como conseguir isso?
Caused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn:
Também é mais limpo de usar @JoinTable
quando uma Entidade pode ser a criança em vários relacionamentos pai / filho com diferentes tipos de pais. Para acompanhar o exemplo de Behrang, imagine que uma Tarefa possa ser filha de Projeto, Pessoa, Departamento, Estudo e Processo.
A task
tabela deve ter 5 nullable
campos de chave estrangeira? Eu acho que não...
É a única solução para mapear uma associação ManyToMany: você precisa de uma tabela de junção entre as duas tabelas de entidades para mapear a associação.
Também é usado para associações OneToMany (geralmente unidirecionais) quando você não deseja adicionar uma chave estrangeira na tabela do lado muitos e, assim, mantê-lo independente do lado.
Pesquise @JoinTable na documentação do hibernate para obter explicações e exemplos.
Ele permite que você lide com o relacionamento Muitos para Muitos. Exemplo:
Table 1: post
post has following columns
____________________
| ID | DATE |
|_________|_________|
| | |
|_________|_________|
Table 2: user
user has the following columns:
____________________
| ID |NAME |
|_________|_________|
| | |
|_________|_________|
Ingressar na tabela permite criar um mapeamento usando:
@JoinTable(
name="USER_POST",
joinColumns=@JoinColumn(name="USER_ID", referencedColumnName="ID"),
inverseJoinColumns=@JoinColumn(name="POST_ID", referencedColumnName="ID"))
irá criar uma tabela:
____________________
| USER_ID| POST_ID |
|_________|_________|
| | |
|_________|_________|
@ManyToMany
associaçõesNa maioria das vezes, você precisará usar a @JoinTable
anotação para especificar o mapeamento de um relacionamento de tabela muitos para muitos:
Portanto, supondo que você tenha as seguintes tabelas de banco de dados:
Na Post
entidade, você mapeará esse relacionamento, assim:
@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<>();
A @JoinTable
anotação é usada para especificar o nome da tabela por meio do name
atributo, bem como a coluna Chave Externa que faz referência à post
tabela (por exemplo, joinColumns
) e a coluna Chave Estrangeira na post_tag
tabela de links que faz referência à Tag
entidade por meio do inverseJoinColumns
atributo.
Observe que o atributo em cascata da
@ManyToMany
anotação está definido comoPERSIST
eMERGE
somente porque a cascataREMOVE
é uma má ideia, já que a instrução DELETE será emitida para o outro registro pai,tag
no nosso caso, não para opost_tag
registro. Para mais detalhes sobre este tópico, consulte este artigo .
@OneToMany
AssociaçõesAs @OneToMany
associações unidirecionais , que carecem de@JoinColumn
mapeamento, se comportam como relacionamentos de tabela muitos para muitos, em vez de um para muitos.
Portanto, supondo que você tenha os seguintes mapeamentos de entidade:
@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
}
O Hibernate assumirá o seguinte esquema de banco de dados para o mapeamento de entidade acima:
Como já explicado, o @OneToMany
mapeamento JPA unidirecional se comporta como uma associação muitos-para-muitos.
Para personalizar a tabela de links, você também pode usar a @JoinTable
anotação:
@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<>();
E agora, a tabela de links será chamada post_comment_ref
e as colunas Foreign Key serão post_id
, para a post
tabela e post_comment_id
para a post_comment
tabela.
@OneToMany
Associações unidirecionais não são eficientes; portanto, é melhor usar@OneToMany
associações bidirecionais ou apenas o@ManyToOne
lado. Confira este artigo para obter mais detalhes sobre este tópico.