web-dev-qa-db-fra.com

object fait référence à une instance transitoire non enregistrée - enregistrez l'instance transitoire avant le vidage

Je reçois le message d'erreur suivant lorsque je sauvegarde l'objet avec Hibernate 

object references an unsaved transient instance - save the transient instance before flushing
466
Tushar Ahirrao

Vous devez inclure cascade="all" (si vous utilisez xml) ou cascade=CascadeType.ALL (si vous utilisez des annotations) dans le mappage de votre collection.

Cela est dû au fait que vous avez une collection dans votre entité et que cette collection contient un ou plusieurs éléments qui ne sont pas présents dans la base de données. En spécifiant les options ci-dessus, vous indiquez à hibernate de les enregistrer dans la base de données lors de l'enregistrement de leur parent.

635
Bozho

Je crois que cela pourrait être juste une réponse répétée, mais juste pour clarifier, je l’ai eu sur un mappage @OneToOne ainsi qu’un @OneToMany. Dans les deux cas, il s'agissait du fait que l'objet Child que j'ajoutais à Parent n'était pas encore enregistré dans la base de données. Donc, quand j'ai ajouté la Child à la Parent, puis enregistré la Parent, Hibernate lançait le message "object references an unsaved transient instance - save the transient instance before flushing" lors de l'enregistrement du parent.

L'ajout du cascade = {CascadeType.ALL} à la référence Parent's à la Child a résolu le problème dans les deux cas. Cela a sauvé la Child et la Parent.

Désolé pour les réponses répétées, je voulais juste clarifier davantage pour les gens.

@OneToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "performancelog_id")
public PerformanceLog getPerformanceLog() {
    return performanceLog;
}
182
McDonald Noland

Cela se produit lorsque vous enregistrez un objet lorsque Hibernate pense avoir besoin de sauvegarder un objet associé à celui que vous enregistrez. 

J'avais ce problème et je ne voulais pas enregistrer les modifications apportées à l'objet référencé. Je voulais donc que le type de cascade soit NONE. 

L'astuce consiste à s'assurer que l'ID et la VERSION de l'objet référencé sont définis de sorte que Hibernate ne pense pas que l'objet référencé est un nouvel objet à sauvegarder. Cela a fonctionné pour moi.

Examinez toutes les relations de la classe que vous enregistrez pour élaborer les objets associés (et les objets associés des objets associés) et assurez-vous que l'ID et la VERSION sont définis dans tous les objets de l'arborescence des objets.

50
Cookalino

Ou, si vous souhaitez utiliser des "pouvoirs" minimaux (par exemple, si vous ne voulez pas de suppression en cascade) pour obtenir ce que vous voulez, utilisez 

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;

...

@Cascade({CascadeType.SAVE_UPDATE})
private Set<Child> children;
24
Haris Osmanagić

Dans mon cas, cela est dû à l'absence de CascadeType du côté @ManyToOne de la relation bidirectionnelle. Pour être plus précis, j'avais CascadeType.ALL sur @OneToMany et ne l'avais pas sur @ManyToOne. L'ajout de CascadeType.ALL à @ManyToOne a résolu le problème . Un-à-plusieurs côté:

@OneToMany(cascade = CascadeType.ALL, mappedBy="globalConfig", orphanRemoval = true)
private Set<GlobalConfigScope>gcScopeSet;

Plusieurs-à-un côté (a ​​causé le problème)

@ManyToOne
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;

Plusieurs-à-un (corrigé en ajoutant CascadeType.PERSIST)

@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
16
allap

Cela s'est produit lors de la persistance d'une entité dans laquelle l'enregistrement existant dans la base de données avait une valeur NULL pour le champ annoté avec @Version (pour un verrouillage optimiste). La mise à jour de la valeur NULL à 0 dans la base de données a corrigé cela.

14
dukethrash

Ce n'est pas la seule raison de l'erreur. Je l'ai rencontré tout à l'heure pour une faute de frappe dans mon codage, qui, je crois, définit la valeur d'une entité déjà sauvegardée.

X x2 = new X();
x.setXid(memberid); // Error happened here - x was a previous global entity I created earlier
Y.setX(x2);

J'ai repéré l'erreur en trouvant exactement quelle variable a causé l'erreur (dans ce cas, String xid). J'ai utilisé une catch autour de tout le bloc de code qui a sauvegardé l'entité et imprimé les traces.

{
   code block that performed the operation
} catch (Exception e) {
   e.printStackTrace(); // put a break-point here and inspect the 'e'
   return ERROR;
}
10
nanospeck

Si votre collection est nullable, essayez simplement: object.SetYouColection(null);

6
Joabe Lucena

N'utilisez pas Cascade.All avant d'avoir à le faire. Role et Permission ont une relation bidirectionnelle manyToMany. Alors le code suivant fonctionnerait 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);

tandis que si l’objet est juste un "nouveau" objet, la même erreur serait renvoyée.

5
Tiina

Pour ajouter mes 2 cents, j’ai eu le même problème lorsque j’ai accidentellement envoyé null comme ID. Le code ci-dessous représente mon scénario (et OP n'a mentionné aucun scénario spécifique).

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);

Ici, je mets l’identifiant de service existant sur une nouvelle instance d’employé sans obtenir d’abord l’entité de service, car je ne souhaite pas qu’une autre requête de sélection soit déclenchée.

Dans certains scénarios, deptId PKID vient sous la forme null à partir de la méthode d'appel et j'obtiens la même erreur. 

Alors, surveillez les valeurs null pour PK ID

4
manikanta

je reçois cette erreur quand j'utilise 

getSession().save(object)

mais cela fonctionne sans problème quand j'utilise 

getSession().saveOrUpdate(object) 
3
acpuma

à côté de toutes les autres bonnes réponses, cela peut arriver si vous utilisez merge pour conserver un objet et oubliez accidentellement d'utiliser la référence fusionnée de l'objet dans la classe parente. considérons l'exemple suivant

merge(A);
B.setA(A);
persist(B);

Dans ce cas, vous fusionnez A mais vous oubliez d'utiliser l'objet fusionné de A. pour résoudre le problème, vous devez réécrire le code comme ceci.

A=merge(A);//difference is here
B.setA(A);
persist(B);
3
Hossein Nasr

Par souci d'exhaustivité: A

org.hibernate.TransientPropertyValueException 

avec message

object references an unsaved transient instance - save the transient instance before flushing

se produira également lorsque vous essayez de persister/fusionner une entité avec une référence à une autre entité qui se trouve être détaché .

1
Ralf

Si vous utilisez Spring Data JPA, l'ajout de l'annotation @Transactional à votre implémentation de service résoudrait le problème.

1
Anony

Une autre raison possible: dans mon cas, j’essayais de sauver l’enfant avant de sauver le parent, sur une toute nouvelle entité.

Le code ressemblait à ceci dans un modèle User.Java:

this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.setNewPassword(password);
this.timeJoin = new Date();
create();

La méthode setNewPassword () crée un enregistrement PasswordHistory et l'ajoute à la collection d'historique dans User. Comme l'instruction create () n'avait pas encore été exécutée pour le parent, celui-ci tentait de sauvegarder dans une collection d'une entité qui n'avait pas encore été créée. Tout ce que je devais faire pour résoudre ce problème était de déplacer l'appel setNewPassword () après l'appel de create ().

this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.timeJoin = new Date();
create();
this.setNewPassword(password);
1
Jeremy Goodell

J'ai aussi fait face à la même situation. En définissant les annotations suivantes au-dessus de la propriété, il a été résolu de résoudre l’exception demandée.

L'exception j'ai fait face.

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

Pour surmonter, l'annotation que j'ai utilisée.

    @OneToMany(cascade = {CascadeType.ALL})
    @Column(name = "ListOfCarsDrivenByDriver")
    private List<Car_OneToMany> listOfCarsBeingDriven = new ArrayList<Car_OneToMany>();

Ce qui a poussé Hibernate à lancer l'exception:

Cette exception est renvoyée vers votre console car l'objet enfant que j'attache à l'objet parent n'est pas présent dans la base de données à ce moment.

En fournissant @OneToMany(cascade = {CascadeType.ALL}), il indique à Hibernate de les enregistrer dans la base de données lors de l'enregistrement de l'objet parent. 

1
Dulith De Costa

Il existe une autre possibilité pouvant entraîner cette erreur en veille prolongée. Vous pouvez définir une référence non enregistrée de votre objet A sur une entité attachée B et souhaiter conserver l'objet C. Même dans ce cas, vous obtiendrez l'erreur susmentionnée.

1
Hossein Nasr

Je pense que c’est parce que vous avez essayé de conserver un objet qui contient une référence à un autre objet qui n’est pas encore existant. C’est pourquoi, dans le "côté DB", essayez de mettre une référence à une ligne qui n’existe pas

0
CrisMon_01

Cas 1: Je recevais cette exception lorsque j'essayais de créer un parent et d'enregistrer cette référence parent pour son enfant, puis une autre requête DELETE/UPDATE (JPQL). Je viens donc de vider () l'entité nouvellement créée après la création du parent et après la création de l'enfant avec la même référence parent. Cela a fonctionné pour moi.

Cas 2: 

Classe parent

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;
    . 
    .
    .
}

Classe Enfant:

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;
    .
    .

}

Dans le cas ci-dessus où parent (Référence) et enfant (RéférenceAdditionalDetails) ont une relation OneToOne et lorsque vous essayez de créer une entité Référence, puis son enfant (RéférenceAdditionalDetails), vous obtenez la même exception. Donc, pour éviter l'exception, vous devez définir la valeur null pour la classe enfant, puis créer le parent. (Exemple de code)

.
.
reference.setRefAddDetails(null);
reference = referenceDao.create(reference);
entityManager.flush();
.
.

Un moyen simple de résoudre ce problème consiste à enregistrer les deux entités . Tout d'abord, enregistrez l'entité enfant, puis enregistrez l'entité parent . L'entité parent dépend de l'entité enfant pour la valeur de la clé étrangère.

Ci-dessous, simple examen d'une relation personnelle

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);
0
shashigura

Il y a tellement de possibilités de cette erreur que d'autres possibilités se trouvent également dans les pages d'ajout ou d'édition. Dans mon cas, j'essayais de sauvegarder un objet AdvanceSalary. Le problème est que lors de la modification, AdvanceSalary employee.employee_id est null, car lors de la modification, je n'ai pas défini employee.employee_id. J'ai créer un champ caché et le définir. mon code fonctionne absolument 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;
        }

    }
0
Ravindra

Une cause possible de l'erreur est l'inexistence de la définition de la valeur de l'entité mère; Par exemple, pour une relation département-employés, vous devez écrire ceci afin de corriger l'erreur:

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);
0
pheromix

J'ai fait face à cette exception quand je ne persistais pas dans l'objet parent mais que je sauvais l'enfant. Pour résoudre le problème, dans la même session, j'ai persisté les objets enfant et parent et utilisé CascadeType.ALL sur le parent. 

0
tadtab

Ce problème m'est arrivé lorsque j'ai créé une nouvelle entité et une entité associée dans une méthode marquée comme @Transactional, puis effectué une requête avant de sauvegarder. 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);
}

Pour résoudre ce problème, j'ai effectué la requête avant de créer la nouvelle entité. 

0
mad_fox