web-dev-qa-db-fra.com

org.hibernate.TransientObjectException: l'objet fait référence à une instance transitoire non enregistrée - enregistrez l'instance transitoire avant le vidage

Dans mon projet, j'ai des entités User, Role, UserRole et BloodGroup. Premièrement, je prends List<BloodGroup> dans la base de données et le règle sur User. Ensuite, je donne User et Role entites à UserRole. Après cela, j'insère User dans la base de données, puis j'essaie d'insérer UserRole, mais je reçois une erreur. Quand je regarde dans DB, l'ID de BloodGroup n'est pas inséré dans la table User.

Si je choisis la première BloodGroup de la liste, j'obtiens une erreur. Les autres options sont normales.

Je regarde Internet, j'ai trouvé cascade = CascadeType.ALL, mais cela ajoute les mêmes données à BloodGroup, ce qui signifie que j'ai plus de Arh + BloodGroup.

Les entités:

@Entity
@Table(name="USERS")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long userid;

    @OneToMany(mappedBy="user")
    private List<Userrole> userroles;

    //bi-directional many-to-one association to Bloodgroup
    @ManyToOne
    @JoinColumn(name="BLOODGRUPID")
    private Bloodgroup bloodgroup;

}

@Entity
public class Bloodgroup implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int bloodgroupid;

    private String bloodgroupname;

    @OneToMany(mappedBy="bloodgroup")
    private List<User> users;

}

@Entity
public class Userrole implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long userroleid;

    private Timestamp createddate;

    private Timestamp deleteddate;

    private String isactive;

    //bi-directional many-to-one association to Role
    @ManyToOne
    @JoinColumn(name="ROLEID")
    private Role role;

    //bi-directional many-to-one association to User
    @ManyToOne
    @JoinColumn(name="USERID")
    private User user;

}

Manette:

user.setBloodgroup(bloodGroupImpl.getBloodGroupById(bGroup));
user.setUserid(userImpl.insertUserProfile(user));
userRoleImpl.insertUserRole(user,role);

DAO:

public void insertUserRole(User user, Role role) {
    Session session =getHibernateTemplate().getSessionFactory().getCurrentSession();
    Userrole uRole = new Userrole();
    uRole.setIsactive("1");
    uRole.setRole(role);
    uRole.setUser(user);        
    session.save(uRole);
    session.flush();        
}


public void insertUserProfile(User user) {
    Session session = getHibernateTemplate().getSessionFactory().getCurrentSession();
    session.save(user);
}

Bûche:

Hibernate: 
insert 
into
    IU.Userrole
    (userroleid, createddate, deleteddate, isactive, ROLEID, USERID) 
values
    (default, ?, ?, ?, ?, ?)

05.Şub.2012 19:23:29 com.Sun.faces.application.ActionListenerImpl processAction
SEVERE: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.iu.eblood.model.Bloodgroup
javax.faces.el.EvaluationException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.iu.eblood.model.Bloodgroup
    at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.Java:102)
    at com.Sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.Java:102)
    at javax.faces.component.UICommand.broadcast(UICommand.Java:315)
    at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.Java:775)
    at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.Java:1267)
    at com.Sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.Java:82)
    at com.Sun.faces.lifecycle.Phase.doPhase(Phase.Java:103)
    at com.Sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.Java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.Java:310)
    at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:305)
    at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:210)
    at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.Java:198)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:76)
    at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:243)
    at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:210)
    at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.Java:198)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:76)
    at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:243)
    at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:210)
    at org.Apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.Java:224)
    at org.Apache.catalina.core.StandardContextValve.invoke(StandardContextValve.Java:169)
    at org.Apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.Java:472)
    at org.Apache.catalina.core.StandardHostValve.invoke(StandardHostValve.Java:168)
    at org.Apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.Java:98)
    at org.Apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.Java:928)
    at org.Apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.Java:118)
    at org.Apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.Java:407)
    at org.Apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.Java:987)
    at org.Apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.Java:539)
    at org.Apache.Tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.Java:300)
    at Java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.Java:886)
    at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:908)
    at Java.lang.Thread.run(Thread.Java:662)
20
eaktas

votre problème sera résolu en définissant correctement les dépendances en cascade ou en enregistrant les entités référencées avant d'enregistrer l'entité faisant référence. Définir la cascade est vraiment délicat à obtenir, à cause de toutes les variations subtiles dans leur utilisation.

Voici comment vous pouvez définir des cascades:

@Entity
public class Userrole implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long userroleid;

    private Timestamp createddate;

    private Timestamp deleteddate;

    private String isactive;

    //bi-directional many-to-one association to Role
    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="ROLEID")
    private Role role;

    //bi-directional many-to-one association to User
    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="USERID")
    private User user;

}

Dans ce scénario, chaque fois que vous enregistrez, mettez à jour, supprimez, etc. Userrole, le rôle et l'utilisateur associés seront également enregistrés, mis à jour ...

Encore une fois, si votre cas d'utilisation exige que vous ne modifiiez pas l'utilisateur ou le rôle lors de la mise à jour de Userrole, sauvegardez simplement l'utilisateur ou le rôle avant de modifier Userrole.

De plus, les relations bidirectionnelles ont une propriété à sens unique. Dans ce cas, l'utilisateur possède le groupe sanguin. Par conséquent, les cascades ne procéderont que de Utilisateur -> Groupe sanguin Encore une fois, vous devez enregistrer l’utilisateur dans la base de données (attachez-la ou rendez-la non transitoire) afin de l’associer à Bloodgroup.

41
John Ericksen

J'ai eu un problème similaire et bien que je me sois assuré que les entités référencées soient sauvegardées en premier, cela continue à échouer avec la même exception. Après des heures d’investigation, il s’est avéré que le problème était lié au fait que la colonne "version" de l’entité référencée était NULL . rangée comme ça:

INSERT INTO project VALUES (1,1,'2013-08-28 13:05:38','2013-08-28 13:05:38','aProject','aa',NULL,'bb','dd','ee','ff','gg','ii',NULL,'LEGACY','0','CREATED',NULL,NULL,1,'0',NULL,NULL,NULL,NULL,'0','0', NULL);

Le problème de ce qui précède est que la colonne de version utilisée par hibernate a été définie sur null, donc même si l'objet a été correctement enregistré, Hibernate l'a considéré comme non enregistré. En s'assurant que la version avait une valeur NON NULL (1 dans ce cas), l'exception a disparu et tout a bien fonctionné.

Je le mets ici au cas où quelqu'un d'autre aurait le même problème, car cela m'a pris beaucoup de temps à comprendre cela et la solution est complètement différente de la précédente.

11
isaac.hazan

J'ai résolu ce problème en ajoutant @Cascade à l'attribut @ManyToOne.

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

@ManyToOne
@JoinColumn(name="BLOODGRUPID")
@Cascade({CascadeType.MERGE, CascadeType.SAVE_UPDATE})
private Bloodgroup bloodgroup;
1
Federico Traiman

Dans mon cas, définir l'objet référencé sur NULL dans mon objet avant la méthode de fusion ou d'enregistrement résout le problème. Dans mon cas, l'objet référencé était un catalogue, il n'est pas nécessaire de l'enregistrer car même.

    fisEntryEB.setCatStatesEB(null);

    (fisEntryEB) getSession().merge(fisEntryEB);
0
Axel Osorio

Au lieu de passer l'objet de référence passé à l'objet enregistré, voici l'explication qui résout mon problème

//wrong
entityManager.persist(role);
user.setRole(role);
entityManager.persist(user)

//right
Role savedEntity= entityManager.persist(role);
user.setRole(savedEntity);
entityManager.persist(user)
0
Jayen Chondigara