Differences @OneToMany, @ManyToMany, @ManyToOne, @OneToOne [duplicate]

9

I wanted to mount a database with Java Hibernate like the one below:

Questions:

  • What is the difference between @OneToMany , @ManyToMany , @ManyToOne , @OneToOne ? And what would your statement look like in Java? Example, it has to be List<Objeto> .

  • I'm thinking of using @OneToOne , an example in the evaluation, would the user be blocked from performing a new evaluation?

asked by anonymous 04.09.2017 / 20:26

1 answer

8

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.

    
04.09.2017 / 21:20