Saltar al contenido

¿Cuál es la mejor manera de eliminar filas en bloque en JPA y al mismo tiempo eliminar en cascada los registros secundarios?

Esta es el arreglo más acertada que encomtrarás aportar, sin embargo obsérvala pausadamente y analiza si se adapta a tu proyecto.

Solución:

Las opciones son:

  1. use la configuración cascade.Remove en el mapeo, cargando entidades y llamando a em.remove en cada
  2. Use la eliminación masiva en la entidad principal y tenga configurada la opción de base de datos “ON DELETE CASCADE” para que la base de datos realice la eliminación en cascada por usted. EclipseLink tiene una anotación @CascadeOnDelete que le permite saber que “ON DELETE CASCADE” está configurado en una relación, o para crearlo si usa JPA para la generación de DDL: http://eclipse.org/eclipselink/documentation/2.5/jpa/extensions /a_cascadeondelete.htm
  3. Utilice varias eliminaciones masivas para eliminar elementos secundarios a los que se pueda hacer referencia antes de eliminar la entidad principal. Por ejemplo: “Eliminar DE Hijo c donde c.padre = (seleccione p de Padre P donde [delete-conditions])” y “Eliminar DE padre p donde [delete-conditions]” Consulte la sección 10.2.4 de http://docs.oracle.com/middleware/1212/toplink/OTLCG/queries.htm#OTLCG94370 para obtener detalles.

¿Cómo funciona JPA CriteriaDelete?

Un JPA CriteriaDelete genera una declaración de eliminación masiva de JPQL, que se analiza en una declaración de eliminación masiva de SQL.

Entonces, el siguiente JPA CriteriaDelete declaración:

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
    
CriteriaDelete delete = builder.createCriteriaDelete(PostComment.class);

Root root = delete.from(PostComment.class);

int daysValidityThreshold = 3;

delete.where(
    builder.and(
        builder.equal(
            root.get("status"), 
            PostStatus.SPAM
        ),
        builder.lessThanOrEqualTo(
            root.get("updatedOn"), 
            Timestamp.valueOf(
                LocalDateTime
                .now()
                .minusDays(daysValidityThreshold)
            )
        )
    )
);

int deleteCount = entityManager.createQuery(delete).executeUpdate();

genera esta consulta de eliminación de SQL:

DELETE FROM
    post_comment
WHERE
    status = 2 AND
    updated_on <= '2020-08-06 10:50:43.115'

Por lo tanto, no hay una cascada a nivel de entidad ya que la eliminación se realiza mediante la instrucción SQL, no a través de la EntityManager.

Eliminación masiva en cascada

Para habilitar la cascada al ejecutar la eliminación masiva, debe usar la cascada de nivel DDL al declarar las restricciones FK.

ALTER TABLE post_comment 
ADD CONSTRAINT FK_POST_COMMENT_POST_ID
FOREIGN KEY (post_id) REFERENCES post 
ON DELETE CASCADE

Ahora, al ejecutar la siguiente declaración de eliminación masiva:

DELETE FROM
    post
WHERE
    status = 2 AND
    updated_on <= '2020-08-02 10:50:43.109'

La base de datos eliminará el post_comment registros que hacen referencia a la post filas que se eliminaron.

La mejor manera de ejecutar DDL es a través de una herramienta de migración de esquema automática, como Flyway, por lo que la definición de clave externa debe residir en un script de migración.

Si está generando los scripts de migración con la herramienta HBM2DLL, entonces, en el PostComment clase, puede usar la siguiente asignación para generar la declaración DDL mencionada anteriormente:

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(foreignKey = @ForeignKey(name = "FK_POST_COMMENT_POST_ID"))
@OnDelete(action = OnDeleteAction.CASCADE)
private Post post;

Si realmente le importa el tiempo que lleva realizar esta eliminación masiva, le sugiero que use JPQL para eliminar sus entidades. Cuando emites un DELETE Consulta JPQL, emitirá directamente una eliminación en esas entidades sin recuperarlas en primer lugar.

int deletedCount = entityManager.createQuery("DELETE FROM Country").executeUpdate(); 

Incluso puede hacer eliminaciones condicionales basadas en algunos parámetros en esas entidades usando la API de consulta como se muestra a continuación

Query query = entityManager.createQuery("DELETE FROM Country c 
                              WHERE c.population < :p");
int deletedCount = query.setParameter(p, 100000).executeUpdate();

executeUpdate devolverá el número de filas eliminadas una vez que se complete la operación.

Si tiene el tipo de cascada adecuado en sus entidades como CascadeType.ALL (o) CascadeType.REMOVEentonces la consulta anterior hará el truco por ti.

@Entity
class Employee 

    @OneToOne(cascade=CascadeType.REMOVE)
    private Address address;


Para más detalles, echa un vistazo a esto y esto.

Valoraciones y reseñas

Te invitamos a respaldar nuestra publicación poniendo un comentario y puntuándolo te lo agradecemos.

¡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 *