Unidirectional vs bidirectional mapping
First of all, it should be noted that each of the relationships @OneToOne
, @OneToMany
, @ManyToOne
and @ManyToMany
may be unidirectional or bidirectional.
In the unidirectional relationship between two entities A and B, starting with entity A, I come easily to an instance of entity B, but I cannot easily do the opposite.
Already in the bi-directional relationship, I can also from the entity B, easily navigate back to the entity A.
Mapping @ManyToOne
unidirectional
The @ManyToOne
means many-to-1. In this your example (I will assume that the field categoria
on the table evento
should be called categoria_id
), we would have it:
@Entity
@Table(name = "evento")
public class Evento {
// ... Outros campos ...
@ManyToOne
@JoinColumn(name = "categoria_id")
private Categoria categoria;
// ... Outros campos e métodos ...
public Categoria getCategoria() {
return categoria;
}
}
The side Many
is the class that involves it all, in case Evento
. The side One
is that of the related entity, in the case of Categoria
. That is, many events for a category. The same rule also applies to @ManyToOne
, @OneToOne
and @ManyToMany
(we will see more about them below).
This is because an event has only one category, but a category can have many events. With this mapping, we can do this:
Evento e = ...;
Categoria c = e.getCategoria();
Mapping @OneToMany
unidirectional
The @OneToMany
is the opposite of @ManyToOne
, ie is the 1-to-many. For example, we could do this:
@Entity
@Table(name = "categoria")
public class Categoria {
// ... Outros campos ...
@OneToMany
@JoinColumn(name = "categoria_id") // Esta coluna está na tabela "evento".
private List<Evento> eventos;
// ... Outros campos e métodos ...
public List<Evento> getEventos() {
return eventos;
}
}
With this mapping, we can do this:
Categoria c = ...;
List<Evento> eventos = c.getEventos();
Mappings @OneToMany
and @ManyToOne
bidirectional
If you have the above two cases at the same time, where from Evento
I arrive in category and from Categoria
I arrive in Evento
, the result will be that the mapping will go wrong. Why? Because JPA will see two different mappings, one of them Evento
for Categoria
and a different mapping of Categoria
for Evento
. It turns out that these two mappings are one!
That’s where the field comes in mappedBy
:
@Entity
@Table(name = "evento")
public class Evento {
// ... Outros campos ...
@ManyToOne
@JoinColumn(name = "categoria_id")
private Categoria categoria;
// ... Outros campos e métodos ...
public Categoria getCategoria() {
return categoria;
}
}
@Entity
@Table(name = "categoria")
public class Categoria {
// ... Outros campos ...
@OneToMany(mappedBy = "categoria")
private List<Evento> eventos;
// ... Outros campos e métodos ...
public List<Evento> getEventos() {
return eventos;
}
}
In this bi-directional relationship, the mappedBy
says that the other side of the relationship that owns it and that the field that shapes it is called categoria
. Note that this is the field name of the Java class, not the field name in the database!
In general, it is recommended that the side of the relationship end with the toOne
is the owner of the relationship.
It’s important in two-way relationships, to always connect the two sides of the relationship before persisting in the EntityManager
:
Evento e = ...;
Categoria c = ...;
e.setCategoria(c);
c.eventos.add(e);
Mapping @OneToOne
If you use the @OneToOne
You model case 1-to-1. You can make an evaluation belong to only one person, but in this type of relationship, you also have that one person can only have an evaluation.
You would do it like this:
@Entity
@Table(name = "avaliacao")
public class Avaliacao {
// ... Outros campos ...
@OneToOne
@JoinColumn(name = "pessoa_id")
private Pessoa pessoa;
// ... Outros campos e métodos ...
public Pessoa getPessoa() {
return pessoa;
}
}
With that, you can do it:
Avaliacao a = ...;
Pessoa avaliado = a.getPessoa();
To do otherwise, it is necessary that the relationship is bidirectional:
@Entity
@Table(name = "pessoa")
public class Pessoa {
// ... Outros campos ...
@OneToOne(mappedBy = "pessoa")
private Avaliacao avaliacao;
// ... Outros campos e métodos ...
public Avaliacao getAvaliacao() {
return avaliacao;
}
}
And then, having the two-way relationship:
Pessoa p = ...;
Avaliacao a = p.getAvaliacao();
Again, in the case of two-way relationships, one should always connect the two sides of the relationship before persisting in the EntityManager
:
Pessoa p = ...;
Avaliacao a = ...;
a.setPessoa(p);
p.setAvaliacao(a);
Mapping @ManyToMany
Your diagram has no case where a many-to-many relationship exists. So let’s come up with a:
One type of pizza have several types of ingredients.
One type of ingredient can be part of several types of pizza.
And let’s assume we have the table pizza
, the table ingrediente
and an intermediate table pizza_ingrediente
, where each row contains the key of the other two tables.
@Entity
@Table(name = "pizza")
public class Pizza {
// ... Outros campos ...
@ManyToMany
@JoinTable(
name = "pizza_ingrediente",
joinColumns = @JoinColumn(name = "pizza_id"),
inverseJoinColumns = @JoinColumn(name = "ingrediente_id"),
)
private List<Ingrediente> ingredientes;
// ... Outros campos e métodos ...
public List<Ingrediente> getIngredientes() {
return ingredientes;
}
}
The annotation @JoinTable
is responsible for mapping the intermediate table. The joinColumns
represents the side of the entity that owns the relationship (Pizza
) and the inverseJoinColumns
the side of the related entity (Ingrediente
). With all this, it is possible then to do this:
Pizza p = ...;
List<Ingrediente> ingredientes = p.getIngredientes();
To make the relationship bi-directional, again we have the mappedBy
:
@Entity
@Table(name = "ingrediente")
public class Ingrediente {
// ... Outros campos ...
@ManyToMany(mappedBy = "ingredientes")
private List<Pizza> pizzas;
// ... Outros campos e métodos ...
public List<Pizza> getPizzas() {
return pizzas;
}
}
And then we can do that too:
Ingrediente i = ...;
List<Pizza> pizzas = i.getPizzas();
And again, we have to remember to relate the two sides:
Ingrediente mussarela = ...;
Ingrediente tomate = ...;
Ingrediente presunto = ...;
Ingrediente ovo = ...;
Pizza napolitana = ...;
Pizza portuguesa = ...;
napolitana.ingredientes.add(mussarela);
napolitana.ingredientes.add(tomate);
napolitana.ingredientes.add(presunto);
portuguesa.ingredientes.add(mussarela);
portuguesa.ingredientes.add(ovo);
portuguesa.ingredientes.add(presunto);
mussarela.pizzas.add(napolitana);
mussarela.pizzas.add(portuguesa);
presunto.pizzas.add(napolitana);
presunto.pizzas.add(portuguesa);
tomate.pizzas.add(napolitana);
ovo.pizzas.add(portuguesa);
Finally remember this:
If the relationship ends with ToMany
, then you have a list of related entities. It ends with ToOne
, there is only one related entity.
I think it follows the same concept: What is the difference between the relationships between tables?
– Marconi
The way other posts explained I couldn’t understand, but as the guy below explained, I got.
– Felipe Junges