¿Cuál es la diferencia entre CascadeType.REMOVE y orphanRemoval en JPA?

100

Cuál es la diferencia entre

@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }

y

@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }

Este ejemplo es del Tutorial de Java EE, pero todavía no entiendo los detalles.

rand0m86
fuente
La eliminación de huérfanos significa que las entidades dependientes se eliminan cuando se destruye la relación con su entidad "matriz".
Rahul Tripathi
1
Escribió un caso de prueba que podría ilustrar el concepto.
Martin Andersson

Respuestas:

152

Desde aquí : -

Eliminar en cascada

Marcar un campo de referencia con CascadeType.REMOVE (o CascadeType.ALL, que incluye REMOVE) indica que las operaciones de eliminación deben conectarse en cascada automáticamente a los objetos de entidad a los que hace referencia ese campo (un campo de colección puede hacer referencia a varios objetos de entidad):

@Entity
class Employee {
     :
    @OneToOne(cascade=CascadeType.REMOVE)
    private Address address;
     :
}

Remoción de huérfanos

JPA 2 admite un modo de eliminación en cascada adicional y más agresivo que se puede especificar utilizando el elemento orphanRemoval de las anotaciones @OneToOne y @OneToMany:

@Entity
class Employee {
     :
    @OneToOne(orphanRemoval=true)
    private Address address;
     :
}

DIFERENCIA:-

La diferencia entre las dos configuraciones está en la respuesta a la desconexión de una relación. Por ejemplo, como cuando se establece el campo de dirección en nulo o en otro objeto de dirección.

  • Si se especifica orphanRemoval = true, la instancia de dirección desconectada se elimina automáticamente. Esto es útil para limpiar objetos dependientes (por ejemplo, Dirección) que no deberían existir sin una referencia de un objeto propietario (por ejemplo, Empleado).
  • Si solo se especifica cascade = CascadeType.REMOVE, no se realiza ninguna acción automática ya que desconectar una relación no es una
    operación de eliminación .
Rahul Tripathi
fuente
87

Una forma sencilla de comprender la diferencia entre CascadeType.REMOVEy orphanRemoval=true.

Para eliminación de huérfanos: si invoca setOrders(null), las Orderentidades relacionadas se eliminarán en db automáticamente.

Para eliminar cascada: si invoca setOrders(null), las Orderentidades relacionadas NO se eliminarán en db automáticamente.

estudiar
fuente
2
eliminar === eliminar
Abdull
9

Supongamos que tenemos una entidad secundaria y una entidad matriz. Un padre puede tener varios hijos.

@Entity
class parent {
  //id and other fields
 @OneToMany (orphanRemoval = "true",cascade = CascadeType.REMOVE)
   Set<Person> myChildern;
}

OrphanRemoval es un concepto ORM, indica si el niño es huérfano. también debe eliminarse de la base de datos.

Un niño queda huérfano cuando no se puede acceder a él desde su padre. Por ejemplo, si eliminamos el conjunto de objetos Persona (configurándolo en un conjunto vacío) o lo reemplazamos con un conjunto nuevo, el padre ya no podrá acceder a los hijos del conjunto anterior y los hijos quedarán huérfanos, por lo que los hijos están condenados a ser eliminado en la base de datos también.

CascadeType.REMOVE es un concepto de nivel de base de datos e indica si se elimina el padre, todos sus registros relacionados en la tabla secundaria deben eliminarse.

Señor q
fuente
2

Prácticamente, la diferencia radica en si está intentando actualizar los datos (PATCH) o reemplazarlos por completo (PUT)

Supongamos que elimina el customerque el uso cascade=REMOVEtambién eliminará los pedidos de los clientes que parecen intencionados y útiles.

@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }

Ahora digamos que actualiza un customercon orphanRemoval="true"eliminará todos los pedidos anteriores y los reemplazará con el proporcionado. ( PUTen términos de REST API)

@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }

Sin orphanRemovalviejos pedidos se mantendrían. ( PATCHen términos de REST API)

garg10may
fuente
1

Dado que esta pregunta es muy común, esta respuesta se basa en este artículo que escribí en mi blog.

CascadeType.REMOVE

La CascadeType.REMOVEestrategia, que puede configurar explícitamente:

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

o heredarlo implícitamente de la CascadeType.ALLestrategia:

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

le permite propagar la removeoperación de la entidad principal a sus entidades secundarias.

Entonces, si buscamos la Postentidad padre junto con su commentscolección y eliminamos la postentidad:

Post post = entityManager.createQuery("""
    select p
    from Post p
    join fetch p.comments
    where p.id = :id
    """, Post.class)
.setParameter("id", postId)
.getSingleResult();

entityManager.remove(post);

Hibernate ejecutará tres declaraciones de eliminación:

DELETE FROM post_comment 
WHERE id = 2

DELETE FROM post_comment 
WHERE id = 3

DELETE FROM post 
WHERE id = 1

Las PostCommententidades secundarias se eliminaron debido a la CascadeType.REMOVEestrategia, que actuó como si también elimináramos las entidades secundarias.

La estrategia de remoción de huérfanos

La estrategia de eliminación de huérfanos, que debe establecerse mediante el orphanRemovalatributo:

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

le permite eliminar la fila de la tabla secundaria al eliminar la entidad secundaria de la colección.

Entonces, si cargamos la Postentidad junto con su commentscolección y eliminamos la primera PostCommentde la commentscolección:

Post post = entityManager.createQuery("""
    select p
    from Post p
    join fetch p.comments c
    where p.id = :id
    order by p.id, c.id
    """, Post.class)
.setParameter("id", postId)
.getSingleResult();

post.remove(post.getComments().get(0));

Hibernate ejecutará una instrucción DELETE para la post_commentfila de la tabla asociada :

DELETE FROM post_comment 
WHERE id = 2

Para obtener más detalles sobre este tema, consulte también este artículo .

Vlad Mihalcea
fuente