PersistentObjectException: entidad separada pasada para persistir lanzada por JPA e Hibernate

Resuelto Paul Sanwald asked hace 12 años • 24 respuestas

Tengo un modelo de objetos persistentes JPA que contiene una relación de muchos a uno: an Accounthas many Transactions. A Transactiontiene uno Account.

Aquí hay un fragmento del código:

@Entity
public class Transaction {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne(cascade = {CascadeType.ALL},fetch= FetchType.EAGER)
    private Account fromAccount;
....

@Entity
public class Account {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @OneToMany(cascade = {CascadeType.ALL},fetch= FetchType.EAGER, mappedBy = "fromAccount")
    private Set<Transaction> transactions;

Puedo crear un Accountobjeto, agregarle transacciones y conservar el Accountobjeto correctamente. Pero, cuando creo una transacción, usando una Cuenta existente ya persistente y persistiendo la Transacción , obtengo una excepción:

Causado por: org.hibernate.PersistentObjectException: entidad separada pasada para persistir: com.paulsanwald.Account en org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:141)

Por lo tanto, puedo conservar una transacción Accountque contiene transacciones, pero no una transacción que tiene un archivo Account. Pensé que esto se debía a que es Accountposible que no esté adjunto, pero este código aún me da la misma excepción:

if (account.getId()!=null) {
    account = entityManager.merge(account);
}
Transaction transaction = new Transaction(account,"other stuff");
 // the below fails with a "detached entity" message. why?
entityManager.persist(transaction);

¿ Cómo puedo guardar correctamente un archivo asociado a un objeto Transactionya persistente ?Account

Paul Sanwald avatar Nov 14 '12 05:11 Paul Sanwald
Aceptado

La solución es simple, simplemente use en CascadeType.MERGElugar de CascadeType.PERSISTo CascadeType.ALL.

He tenido el mismo problema y CascadeType.MERGEme ha funcionado.

Espero que estés ordenado.

ochiWlad avatar Mar 24 '2015 14:03 ochiWlad

Este es un problema típico de coherencia bidireccional. Está bien discutido en este enlace así como en este enlace.

Según los artículos de los 2 enlaces anteriores, debe corregir sus configuradores en ambos lados de la relación bidireccional. Un configurador de ejemplo para el lado Uno está en este enlace.

Un creador de ejemplo para el lado Muchos se encuentra en este enlace.

Después de corregir sus configuradores, desea declarar que el tipo de acceso a la entidad sea "Propiedad". La mejor práctica para declarar el tipo de acceso "Propiedad" es mover TODAS las anotaciones de las propiedades del miembro a los captadores correspondientes. Una gran advertencia es no mezclar los tipos de acceso "Campo" y "Propiedad" dentro de la clase de entidad, de lo contrario, el comportamiento no está definido por las especificaciones JSR-317.

Sym-Sym avatar Nov 21 '2012 19:11 Sym-Sym

Eliminación de la asociación infantil en cascada

Por lo tanto, debe eliminarlo @CascadeType.ALLde la @ManyToOneasociación. Las entidades secundarias no deben conectarse en cascada a las asociaciones principales. Sólo las entidades principales deben conectarse en cascada a entidades secundarias.

@ManyToOne(fetch= FetchType.LAZY)

Observe que configuré el fetchatributo en FetchType.LAZYporque la búsqueda ansiosa es muy mala para el rendimiento.

Estableciendo ambos lados de la asociación

Siempre que tenga una asociación bidireccional, deberá sincronizar ambos lados usando los métodos addChildy removeChilden la entidad principal:

public void addTransaction(Transaction transaction) {
    transcations.add(transaction);
    transaction.setAccount(this);
}

public void removeTransaction(Transaction transaction) {
    transcations.remove(transaction);
    transaction.setAccount(null);
}
Vlad Mihalcea avatar Sep 15 '2019 06:09 Vlad Mihalcea