¿Cuál es el significado de CascadeType.ALL para una asociación @ManyToOne JPA

210

Creo que entendí mal el significado de la conexión en cascada en el contexto de una @ManyToOnerelación.

El caso:

public class User {

   @OneToMany(fetch = FetchType.EAGER)
   protected Set<Address> userAddresses;

}

public class Address {

   @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
   protected User addressOwner;

}

¿Cuál es el significado de la cascade = CascadeType.ALL? Por ejemplo, si elimino una determinada dirección de la base de datos, ¿cómo afecta el hecho de que agregué la cascade = CascadeType.ALLinformación ( Usersupongo)?

forhas
fuente

Respuestas:

360

El significado de CascadeType.ALLes que la persistencia propagará (en cascada) todas las EntityManageroperaciones ( PERSIST, REMOVE, REFRESH, MERGE, DETACH) a las entidades relacionadas.

En su caso, parece ser una mala idea, ya que eliminar una Addressllevaría a eliminar lo relacionado User. Como un usuario puede tener múltiples direcciones, las otras direcciones se convertirían en huérfanas. Sin embargo, el caso inverso (anotar el User) tendría sentido: si una dirección pertenece a un solo usuario, es seguro propagar la eliminación de todas las direcciones que pertenecen a un usuario si se elimina este usuario.

Por cierto: es posible que desee agregar un mappedBy="addressOwner"atributo para Userindicarle al proveedor de persistencia que la columna de unión debe estar en la tabla DIRECCIÓN.

kostja
fuente
55
+1 para la mejor y más breve explicación de mapped Por alguna vez me he encontrado.
Ridcully
44
Sin embargo, podría ser bueno tener CascadeType.ALL en el lado @OneToMany.
mvmn
48

Vea aquí un ejemplo de los documentos de OpenJPA. CascadeType.ALLsignifica que hará todas las acciones.

Citar:

CascadeType.PERSIST: cuando persiste una entidad, también persiste las entidades contenidas en sus campos. Sugerimos una aplicación liberal de esta regla en cascada, porque si EntityManager encuentra un campo que hace referencia a una nueva entidad durante el vaciado, y el campo no usa CascadeType.PERSIST, es un error.

CascadeType.REMOVE: al eliminar una entidad, también elimina las entidades contenidas en este campo.

CascadeType.REFRESH: al actualizar una entidad, también actualice las entidades contenidas en este campo.

CascadeType.MERGE: al fusionar el estado de la entidad, también se fusionan las entidades contenidas en este campo.

Sebastian

seba.wagner
fuente
44
Nuevo en JPA, esta información es útil, pero ¿qué pasa con Separar aquí?
Sarz
1
En CascadeType.DETACH, al separar una entidad, em también separa las entidades en poder de la entidad principal.
Dorian Mejer
29

Como he explicado en este artículo y en mi libro, de alto rendimiento de persistencia de Java , no se debe utilizar CascadeType.ALLen el @ManyToOnepuesto transiciones de estado de la entidad debe propagarse de entidades matrices de los Niños, y no al revés.

El @ManyToOnelado siempre es la asociación Child, ya que asigna la columna de clave externa subyacente.

Por lo tanto, debe mover el CascadeType.ALLde la @ManyToOneasociación al @OneToManylado, que también debe utilizar el mappedByatributo ya que es la relación de tabla de asignación más eficiente de uno a muchos .

Vlad Mihalcea
fuente
18

De la especificación EJB3.0 :

El uso del elemento de anotación en cascada puede usarse para propagar el efecto de una operación a las entidades asociadas. La funcionalidad en cascada se usa más comúnmente en las relaciones padre-hijo.

Si X es una entidad administrada, la operación de eliminación hace que se elimine. La operación de eliminación se conecta en cascada a las entidades a las que hace referencia X, si las relaciones de X a estas otras entidades se anotan con el valor del elemento de anotación cascade = REMOVE o cascade = ALL.

En pocas palabras, las relaciones de entidad definidas con CascadeType.Allgarantizarán que todos los eventos de persistencia tales como persistir, actualizar, fusionar y eliminar que ocurran en el padre, se pasen al hijo. La definición de otras CascadeTypeopciones proporciona al desarrollador un nivel de control más granular sobre cómo la asociación de entidades maneja la persistencia.

Por ejemplo, si tuviera un libro de objetos que contuviera una lista de páginas y agregue un objeto de página dentro de esta lista. Si la @OneToManyanotación que define la asociación entre Libro y Página está marcada como CascadeType.All, persistir en el Libro daría como resultado que la Página también se mantenga en la base de datos.

Kevin Bowersox
fuente
11

En JPA 2.0, si desea eliminar una dirección si la eliminó de una entidad de usuario, puede agregarla orphanRemoval=true(en lugar de CascadeType.REMOVE) a su @OneToMany.

Más explicación entre orphanRemoval=truey CascadeType.REMOVEestá aquí .

Emilien Brigand
fuente
4

Si solo desea eliminar la dirección asignada al usuario y no afectar a la clase de entidad Usuario, debe intentar algo como eso:

@Entity
public class User {
   @OneToMany(mappedBy = "addressOwner", cascade = CascadeType.ALL)
   protected Set<Address> userAddresses = new HashSet<>();
}

@Entity 
public class Addresses {
   @ManyToOne(cascade = CascadeType.REFRESH) @JoinColumn(name = "user_id")
   protected User addressOwner;
}

De esta manera, no necesita preocuparse por usar fetch en las anotaciones. Pero recuerde que al eliminar el usuario, también eliminará la dirección conectada al objeto de usuario.

szachMati
fuente