Saltar al contenido

¿Cuál es la diferencia entre @JoinColumn y mappedBy cuando se usa una asociación JPA @OneToMany?

Solución:

La anotación @JoinColumn indica que esta entidad es la dueño de la relación (es decir: la tabla correspondiente tiene una columna con una clave externa a la tabla referenciada), mientras que el atributo mappedBy indica que la entidad de este lado es la inversa de la relación y el propietario reside en la “otra” entidad. Esto también significa que puede acceder a la otra tabla de la clase que ha anotado con “mappedBy” (relación completamente bidireccional).

En particular, para el código de la pregunta, las anotaciones correctas se verían así:

@Entity
public class Company {
    @OneToMany(mappedBy = "company",
               orphanRemoval = true,
               fetch = FetchType.LAZY,
               cascade = CascadeType.ALL)
    private List<Branch> branches;
}

@Entity
public class Branch {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "companyId")
    private Company company;
}

@JoinColumn podría usarse en ambos lados de la relación. La pregunta era sobre usar @JoinColumn sobre el @OneToMany lado (caso raro). Y el punto aquí está en duplicación de información física (nombre de la columna) junto con consulta SQL no optimizada que producirá algunos UPDATE declaraciones.

Según documentación:

Ya que muchos a uno son (casi) siempre el lado del propietario de una relación bidireccional en la especificación JPA, la asociación de uno a muchos está anotada por @OneToMany(mappedBy=...)

@Entity
public class Troop {
    @OneToMany(mappedBy="troop")
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk")
    public Troop getTroop() {
    ...
} 

Troop tiene una relación bidireccional de uno a muchos con Soldier a través de la propiedad de la tropa. No tiene que (no debe) definir ningún mapeo físico en el mappedBy lado.

Para mapear un bidireccional uno a muchos, con el lado uno a muchos como el lado propietario, tienes que quitar el mappedBy elemento y establezca muchos en uno @JoinColumn como insertable y updatable a falso. Esta solución no está optimizada y producirá algunos UPDATE declaraciones.

@Entity
public class Troop {
    @OneToMany
    @JoinColumn(name="troop_fk") //we need to duplicate the physical information
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk", insertable=false, updatable=false)
    public Troop getTroop() {
    ...
}

Asociación unidireccional de uno a varios

Si usa el @OneToMany anotación con @JoinColumn, entonces tienes una asociación unidireccional, como la que existe entre el padre Post entidad y el niño PostComment en el siguiente diagrama:

Asociación unidireccional de uno a varios

Cuando se usa una asociación unidireccional de uno a muchos, solo el lado principal mapea la asociación.

En este ejemplo, solo el Post entidad definirá un @OneToMany asociación con el niño PostComment entidad:

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "post_id")
private List<PostComment> comments = new ArrayList<>();

Asociación bidireccional de uno a varios

Si usa el @OneToMany con el mappedBy conjunto de atributos, tiene una asociación bidireccional. En nuestro caso, tanto el Post entidad tiene una colección de PostComment entidades secundarias, y la secundaria PostComment la entidad tiene una referencia a la matriz Post entidad, como se ilustra en el siguiente diagrama:

Asociación bidireccional de uno a varios

En el PostComment entidad, la post la propiedad de la entidad se asigna de la siguiente manera:

@ManyToOne(fetch = FetchType.LAZY)
private Post post;

La razón por la que establecimos explícitamente el fetch atribuir a FetchType.LAZY es porque, por defecto, todos @ManyToOne y @OneToOne las asociaciones se obtienen con entusiasmo, lo que puede provocar problemas de consulta N + 1.

En el Post entidad, la comments La asociación se asigna de la siguiente manera:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.ALL,
    orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();

los mappedBy atributo del @OneToMany la anotación hace referencia al post propiedad en el niño PostComment entidad, y, de esta manera, Hibernate sabe que la asociación bidireccional está controlada por el @ManyToOne side, que se encarga de administrar el valor de la columna de clave externa en la que se basa esta relación de tabla.

Para una asociación bidireccional, también necesita tener dos métodos de utilidad, como addChild y removeChild:

public void addComment(PostComment comment) {
    comments.add(comment);
    comment.setPost(this);
}

public void removeComment(PostComment comment) {
    comments.remove(comment);
    comment.setPost(null);
}

Estos dos métodos garantizan que ambos lados de la asociación bidireccional estén sincronizados. Sin sincronizar ambos extremos, Hibernate no garantiza que los cambios de estado de la asociación se propaguen a la base de datos.

¿Cuál elegir?

El unidireccional @OneToMany La asociación no funciona muy bien, por lo que debe evitarla.

Es mejor usar el bidireccional @OneToMany que es más eficiente.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *