Recibo el siguiente error cuando guardo el objeto usando Hibernate
object references an unsaved transient instance - save the transient instance before flushing
Recibo el siguiente error cuando guardo el objeto usando Hibernate
object references an unsaved transient instance - save the transient instance before flushing
Respuestas:
Debe incluir cascade="all"
(si usa xml) o cascade=CascadeType.ALL
(si usa anotaciones) en su mapeo de colección.
Esto sucede porque tiene una colección en su entidad, y esa colección tiene uno o más elementos que no están presentes en la base de datos. Al especificar las opciones anteriores, le dice a hibernate que las guarde en la base de datos cuando guarde su padre.
Creo que esto podría ser solo una respuesta repetida, pero solo para aclarar, obtuve esto en un @OneToOne
mapeo y a @OneToMany
. En ambos casos, fue el hecho de que el Child
objeto que estaba agregando Parent
no estaba guardado en la base de datos todavía. Así que cuando he añadido el Child
de la Parent
, entonces guardado el Parent
, Hibernate lanzaba el "object references an unsaved transient instance - save the transient instance before flushing"
mensaje al guardar el Padre.
Añadiendo el cascade = {CascadeType.ALL}
en la Parent's
referencia al Child
resuelto el problema en ambos casos. Esto salvó el Child
y el Parent
.
Perdón por las respuestas repetidas, solo quería aclarar más para la gente.
@OneToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "performancelog_id")
public PerformanceLog getPerformanceLog() {
return performanceLog;
}
new MyEntity
(sin sincronizarlo con la base de datos, vaciado), en lugar de obtener su instancia sincronizada de la base de datos. Hacer consultas de Hibernate usando esa instancia le informa que lo que espera que esté en la base de datos difiere de lo que tiene en la memoria de su aplicación. En este caso, simplemente sincronice / obtenga la instancia de su entidad de DB y úsela. No se necesita CascadeType.ALL entonces.
Esto sucede al guardar un objeto cuando Hibernate cree que necesita guardar un objeto asociado con el que está guardando.
Tuve este problema y no quería guardar los cambios en el objeto referenciado, así que quería que el tipo de cascada sea NINGUNO.
El truco es asegurarse de que la ID y la VERSIÓN en el objeto referenciado estén configuradas para que Hibernate no piense que el objeto referenciado es un objeto nuevo que necesita guardarse. Esto funcionó para mí.
Mire todas las relaciones en la clase que está guardando para resolver los objetos asociados (y los objetos asociados de los objetos asociados) y asegúrese de que la ID y la VERSIÓN estén establecidas en todos los objetos del árbol de objetos.
Como expliqué en este artículo cuando uso JPA e Hibernate, una entidad puede estar en uno de los siguientes 4 estados:
Nuevo : un objeto recién creado que nunca se ha asociado con una sesión de hibernación (también conocido como contexto de persistencia) y que no está asignado a ninguna fila de la tabla de la base de datos se considera en estado nuevo o transitorio.
Para ser persistente, necesitamos llamar explícitamente el persist
método o hacer uso del mecanismo de persistencia transitiva.
Persistente : una entidad persistente se ha asociado con una fila de la tabla de la base de datos y está siendo administrada por el Contexto de persistencia actualmente en ejecución.
Cualquier cambio realizado en dicha entidad se detectará y propagará a la base de datos (durante el tiempo de descarga de la sesión).
Independiente : una vez que el contexto de persistencia actualmente en ejecución se cierra, todas las entidades administradas previamente se desconectan. Los cambios sucesivos ya no serán rastreados y no se realizará una sincronización automática de la base de datos.
Eliminado : aunque JPA exige que solo se permita eliminar entidades administradas, Hibernate también puede eliminar entidades separadas (pero solo a través de una remove
llamada al método).
Para mover una entidad de un estado a otro, puede utilizar los persist
, remove
o merge
métodos.
El problema que está describiendo en su pregunta:
object references an unsaved transient instance - save the transient instance before flushing
es causado por asociar una entidad en el estado de Nuevo a una entidad que está en el estado de Administrado .
Esto puede suceder cuando está asociando una entidad secundaria a una colección de uno a varios en la entidad principal, y la colección no realiza cascade
las transiciones de estado de la entidad.
Entonces, como expliqué en este artículo , puede solucionar esto agregando cascada a la asociación de entidades que desencadenó esta falla, de la siguiente manera:
@OneToOne
asociación@OneToOne(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private PostDetails details;
Observe el
CascadeType.ALL
valor que agregamos para elcascade
atributo.
@OneToMany
asociación@OneToMany(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
Nuevamente, el CascadeType.ALL
es adecuado para las asociaciones bidireccionales@OneToMany
.
Ahora, para que la cascada funcione correctamente de forma bidireccional, también debe asegurarse de que las asociaciones padre e hijo estén sincronizadas.
Consulte este artículo para obtener más detalles sobre cuál es la mejor manera de lograr este objetivo.
@ManyToMany
asociación@ManyToMany(
mappedBy = "authors",
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}
)
private List<Book> books = new ArrayList<>();
En una @ManyToMany
asociación, no puede usar CascadeType.ALL
o orphanRemoval
ya que esto propagará la transición del estado de eliminar entidad de una entidad primaria a otra entidad principal.
Por lo tanto, para @ManyToMany
las asociaciones, por lo general, la cascada de módulos CascadeType.PERSIST
o de CascadeType.MERGE
operaciones. Alternativamente, puede expandir eso a DETACH
o REFRESH
.
Para obtener más detalles sobre la mejor manera de asignar una
@ManyToMany
asociación, consulte también este artículo .
O, si desea usar "poderes" mínimos (por ejemplo, si no desea una eliminación en cascada) para lograr lo que desea, use
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
...
@Cascade({CascadeType.SAVE_UPDATE})
private Set<Child> children;
@ManyToMany(cascade={PERSIST, MERGE, REFRESH, DETACH})
(todos menos ELIMINAR) no actualiza en cascada como lo hace Hibernate CascadeType.SAVE_UPDATE
.
En mi caso fue causado por no tener CascadeType
del @ManyToOne
lado de la relación bidireccional. Para ser más precisos, estaba CascadeType.ALL
de @OneToMany
lado y no lo tenía puesto @ManyToOne
. Agregando CascadeType.ALL
a @ManyToOne
resuelto el problema.
Lado uno a muchos :
@OneToMany(cascade = CascadeType.ALL, mappedBy="globalConfig", orphanRemoval = true)
private Set<GlobalConfigScope>gcScopeSet;
Lado de muchos a uno (causó el problema)
@ManyToOne
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
Muchos a uno (arreglado al agregar CascadeType.PERSIST
)
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
Esto ocurrió cuando persistí en una entidad en la que el registro existente en la base de datos tenía un valor NULL para el campo anotado con @Version (para un bloqueo optimista). La actualización del valor NULL a 0 en la base de datos corrigió esto.
Esta no es la única razón del error. Lo encontré hace un momento por un error tipográfico en mi codificación, que creo que estableció un valor de una entidad que ya estaba guardada.
X x2 = new X();
x.setXid(memberid); // Error happened here - x was a previous global entity I created earlier
Y.setX(x2);
Descubrí el error al encontrar exactamente qué variable causó el error (en este caso String xid
). Utilicé un catch
alrededor de todo el bloque de código que salvó a la entidad e imprimió los rastros.
{
code block that performed the operation
} catch (Exception e) {
e.printStackTrace(); // put a break-point here and inspect the 'e'
return ERROR;
}
No lo uses Cascade.All
hasta que realmente tengas que hacerlo. Role
y Permission
tienen manyToMany
relación bidireccional . Entonces el siguiente código funcionaría bien
Permission p = new Permission();
p.setName("help");
Permission p2 = new Permission();
p2.setName("self_info");
p = (Permission)crudRepository.save(p); // returned p has id filled in.
p2 = (Permission)crudRepository.save(p2); // so does p2.
Role role = new Role();
role.setAvailable(true);
role.setDescription("a test role");
role.setRole("admin");
List<Permission> pList = new ArrayList<Permission>();
pList.add(p);
pList.add(p2);
role.setPermissions(pList);
crudRepository.save(role);
mientras que si el objeto es solo "nuevo", arrojaría el mismo error.
Si su colección es anulable, simplemente intente: object.SetYouColection(null);
Para agregar mis 2 centavos, recibí este mismo problema cuando envío accidentalmente null
como ID. El siguiente código muestra mi escenario (y OP no mencionó ningún escenario específico) .
Employee emp = new Employee();
emp.setDept(new Dept(deptId)); // --> when deptId PKID is null, same error will be thrown
// calls to other setters...
em.persist(emp);
Aquí estoy configurando el ID del departamento existente a una nueva instancia de empleado sin obtener primero la entidad del departamento, ya que no quiero que se active otra consulta de selección.
En algunos escenarios, el deptId
PKID proviene null
del método de llamada y obtengo el mismo error.
Por lo tanto, observe los null
valores para PK ID
Este problema me ocurrió cuando creé una nueva entidad y una entidad asociada en un método marcado como @Transactional
, y luego realicé una consulta antes de guardar. Ex
@Transactional
public someService() {
Entity someEntity = new Entity();
AssocaiatedEntity associatedEntity = new AssocaitedEntity();
someEntity.setAssociatedEntity(associatedEntity);
associatedEntity.setEntity(someEntity);
// Performing any query was causing hibernate to attempt to persist the new entity. It would then throw an exception
someDao.getSomething();
entityDao.create(someEntity);
}
Para solucionarlo, realicé la consulta antes de crear la nueva entidad.
además de todas las otras buenas respuestas, esto podría suceder si usas merge
para persistir un objeto y accidentalmente olvidas usar la referencia fusionada del objeto en la clase principal. considera el siguiente ejemplo
merge(A);
B.setA(A);
persist(B);
En este caso, se fusiona A
pero se olvida usar el objeto fusionado de A
. Para resolver el problema, debe volver a escribir el código de esta manera.
A=merge(A);//difference is here
B.setA(A);
persist(B);
También me enfrenté a la misma situación. Al establecer la siguiente anotación sobre la propiedad, se resolvió la excepción solicitada.
La excepción que enfrenté.
Exception in thread "main" java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.model.Car_OneToMany
Para superar, la anotación que utilicé.
@OneToMany(cascade = {CascadeType.ALL})
@Column(name = "ListOfCarsDrivenByDriver")
private List<Car_OneToMany> listOfCarsBeingDriven = new ArrayList<Car_OneToMany>();
Lo que hizo que Hibernate lanzara la excepción:
Esta excepción se produce en su consola porque el objeto secundario que adjunto al objeto primario no está presente en la base de datos en ese momento.
Al proporcionar @OneToMany(cascade = {CascadeType.ALL})
, le dice a Hibernate que los guarde en la base de datos mientras guarda el objeto padre.
En aras de la exhaustividad: A
org.hibernate.TransientPropertyValueException
con mensaje
object references an unsaved transient instance - save the transient instance before flushing
También ocurrirá cuando intente persistir / fusionar una entidad con una referencia a otra entidad que se separa .
Otra posible razón: en mi caso, estaba tratando de salvar al niño antes de salvar al padre, en una entidad nueva.
El código era algo así en un modelo User.java:
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.setNewPassword(password);
this.timeJoin = new Date();
create();
El método setNewPassword () crea un registro PasswordHistory y lo agrega a la colección de historial en Usuario. Como la instrucción create () aún no se había ejecutado para el padre, estaba intentando guardar en una colección de una entidad que aún no se había creado. Todo lo que tuve que hacer para solucionarlo fue mover la llamada setNewPassword () después de la llamada para crear ().
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.timeJoin = new Date();
create();
this.setNewPassword(password);
Hay otra posibilidad que puede causar este error en hibernación. Puede establecer una referencia no guardada de su objeto A
a una entidad adjunta B
y desea conservar el objeto C
. Incluso en este caso, obtendrá el error antes mencionado.
Creo que es porque has intentado persistir un objeto que tiene una referencia a otro objeto que aún no persiste, y por eso intenta en el "lado DB" poner una referencia a una fila que no existe
Una forma simple de resolver este problema es salvar a ambas entidades. primero guarde la entidad secundaria y luego guarde la entidad principal. Porque la entidad principal depende de la entidad secundaria para el valor de la clave externa.
A continuación, un simple examen de la relación uno a uno
insert into Department (name, numOfemp, Depno) values (?, ?, ?)
Hibernate: insert into Employee (SSN, dep_Depno, firstName, lastName, middleName, empno) values (?, ?, ?, ?, ?, ?)
Session session=sf.openSession();
session.beginTransaction();
session.save(dep);
session.save(emp);
Una posible causa del error es la inexistencia del establecimiento del valor de la entidad matriz; por ejemplo, para una relación departamento-empleados, debe escribir esto para corregir el error:
Department dept = (Department)session.load(Department.class, dept_code); // dept_code is from the jsp form which you get in the controller with @RequestParam String department
employee.setDepartment(dept);
Hay tantas posibilidades de este error que algunas otras posibilidades también están en agregar página o editar página. En mi caso, estaba tratando de guardar un objeto AdvanceSalary. El problema es que en la edición AdvanceSalary employee.employee_id es nulo. Porque en la edición no estaba configurado el employee.employee_id. He creado un campo oculto y lo configuré. Mi código funciona absolutamente bien.
@Entity(name = "ic_advance_salary")
@Table(name = "ic_advance_salary")
public class AdvanceSalary extends BaseDO{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "employee_id", nullable = false)
private Employee employee;
@Column(name = "employee_id", insertable=false, updatable=false)
@NotNull(message="Please enter employee Id")
private Long employee_id;
@Column(name = "advance_date")
@DateTimeFormat(pattern = "dd-MMM-yyyy")
@NotNull(message="Please enter advance date")
private Date advance_date;
@Column(name = "amount")
@NotNull(message="Please enter Paid Amount")
private Double amount;
@Column(name = "cheque_date")
@DateTimeFormat(pattern = "dd-MMM-yyyy")
private Date cheque_date;
@Column(name = "cheque_no")
private String cheque_no;
@Column(name = "remarks")
private String remarks;
public AdvanceSalary() {
}
public AdvanceSalary(Integer advance_salary_id) {
this.id = advance_salary_id;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public Long getEmployee_id() {
return employee_id;
}
public void setEmployee_id(Long employee_id) {
this.employee_id = employee_id;
}
}
Me enfrenté a esta excepción cuando no persistí en el objeto padre pero estaba guardando al hijo. Para resolver el problema, en la misma sesión insistí en los objetos secundarios y principales y usé CascadeType.ALL en el principal.
Caso 1: Recibía esta excepción cuando intentaba crear un padre y guardaba esa referencia primaria en su hijo y luego en otra consulta DELETE / UPDATE (JPQL). Así que simplemente elimino () la entidad recién creada después de crear el padre y después de crear el niño usando la misma referencia principal. Funcionó para mí
Caso 2:
Clase de padres
public class Reference implements Serializable {
@Id
@Column(precision=20, scale=0)
private BigInteger id;
@Temporal(TemporalType.TIMESTAMP)
private Date modifiedOn;
@OneToOne(mappedBy="reference")
private ReferenceAdditionalDetails refAddDetails;
.
.
.
}
Clase infantil:
public class ReferenceAdditionalDetails implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@OneToOne
@JoinColumn(name="reference",referencedColumnName="id")
private Reference reference;
private String preferedSector1;
private String preferedSector2;
.
.
}
En el caso anterior, donde padre (Referencia) e hijo (ReferenceAdditionalDetails) tienen una relación OneToOne y cuando intenta crear una entidad de Referencia y luego su hijo (ReferenceAdditionalDetails), le dará la misma excepción. Entonces, para evitar la excepción, debe establecer un valor nulo para la clase secundaria y luego crear el padre (Código de muestra)
.
.
reference.setRefAddDetails(null);
reference = referenceDao.create(reference);
entityManager.flush();
.
.
Mi problema estaba relacionado con @BeforeEach
JUnit. E incluso si guardé las entidades relacionadas (en mi caso@ManyToOne
), obtuve el mismo error.
El problema está relacionado de alguna manera con la secuencia que tengo en mi padre. Si asigno el valor a ese atributo, el problema está resuelto.
Ex. Si tengo la Pregunta de entidad que puede tener algunas categorías (una o más) y la Pregunta de entidad tiene una secuencia:
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "feedbackSeq")
@Id
private Long id;
Tengo que asignar el valor question.setId(1L);
Simplemente haga Constructor de su mapeo en su clase base. Al igual que si desea una relación uno a uno en la entidad A, la entidad B. si está tomando A como clase base, entonces A debe tener un constructor con B como argumento.