One-way vs two-way mappings
First of all, it should be noted that each of the @OneToOne
, @OneToMany
, @ManyToOne
and @ManyToMany
relations can be unidirectional or bidirectional.
In the unidirectional relationship between two entities A and B, starting from entity A, I easily come to an instance of entity B, but I can not easily make the opposite way.
Already in the bidirectional relationship, I can also from entity B, easily navigate back to entity A.
Mapping% of unidirectional%
The @ManyToOne
means many-to-1. In this example (I'm guessing that the @ManyToOne
field in the categoria
table should be called evento
), we would have this:
@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 categoria_id
side is that of the class that involves all this, in the Many
case. The Evento
side is that of the related entity, in the One
case. That is, many events for a category. The same rule also applies to Categoria
, @ManyToOne
and @OneToOne
(we'll see more about them below).
This happens because an event has only one category, but one category can have many events. With this mapping, we can do this:
Evento e = ...;
Categoria c = e.getCategoria();
Mapping% of unidirectional%
@ManyToMany
is the opposite of @OneToMany
, that is, 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 both cases above at the same time, where from @OneToMany
I get into category and from @ManyToOne
I get to Evento
, the result will be that the mapping will go wrong. Because? Because JPA will see two distinct mappings, one from Categoria
to Evento
and a different mapping from Evento
to Categoria
. It happens that these two mappings are one!
This is where the Categoria
: field
@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 bidirectional relation, Evento
says that the other side of the relationship that owns it and that the field that models it is the name mappedBy
. 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 that ends with mappedBy
be the owner of the relationship.
It is important in bidirectional relationships, always connect both sides of the relationship before persisting in categoria
:
Evento e = ...;
Categoria c = ...;
e.setCategoria(c);
c.eventos.add(e);
Mapping toOne
If you use EntityManager
you model the 1-to-1 case. You can make a rating belong to only one person, but in that type of relationship, you also have that one person can only have one rating.
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 this, you can do this:
Avaliacao a = ...;
Pessoa avaliado = a.getPessoa();
To do otherwise, the relationship must be 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 bidirectional relationship:
Pessoa p = ...;
Avaliacao a = p.getAvaliacao();
Again, in the case of bidirectional relationships, you should always bind the two sides of the relationship before persisting in @OneToOne
:
Pessoa p = ...;
Avaliacao a = ...;
a.setPessoa(p);
p.setAvaliacao(a);
Mapping @OneToOne
Your diagram has no case where a many-to-many relationship exists. So let's create one:
One type of pizza has several types of ingredients.
And let's suppose we have the EntityManager
table, the @ManyToMany
table, and an intermediate table pizza
, 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 ingrediente
annotation is responsible for mapping the middle table. The pizza_ingrediente
represents the side of the entity that owns the relationship ( @JoinTable
) and joinColumns
the side of the related entity ( Pizza
). With all this, it is then possible to do this:
Pizza p = ...;
List<Ingrediente> ingredientes = p.getIngredientes();
To make the bidirectional relationship, we again have inverseJoinColumns
:
@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 Ingrediente
, then you have a list of related entities. If it ends with mappedBy
, there is only one related entity.