Reputation: 273
In my project I have User
, Role
, UserRole
and BloodGroup
entities. Firstly I take List<BloodGroup>
from DB and set to User
. Then I give User
and Role
entites to UserRole
. After that I insert User
to DB, then I try to insert UserRole
, but I get an error. When I look to DB, the ID of BloodGroup
isn't inserted in User
table.
If I choose the first BloodGroup
in the list, I get an error. Other options is normal.
I look at the internet, I found cascade = CascadeType.ALL
, but this add same data to BloodGroup
, which means I have more Arh+ BloodGroup
.
The entities:
@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;
}
Controller:
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);
}
Log:
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)
Upvotes: 25
Views: 105145
Reputation: 39
In my case setting the referenced object to NULL in my object before the merge o save method solve the problem, in my case the referenced object was catalog, that doesn't need to be saved, because in some cases I don't have it even.
fisEntryEB.setCatStatesEB(null);
(fisEntryEB) getSession().merge(fisEntryEB);
Upvotes: 1
Reputation: 485
Instead of passing reference object passed the saved object, below is explanation which solve my issue:
//wrong
entityManager.persist(role);
user.setRole(role);
entityManager.persist(user)
//right
Role savedEntity= entityManager.persist(role);
user.setRole(savedEntity);
entityManager.persist(user)
Upvotes: -1
Reputation: 1251
I Solved this problem adding @Cascade to the @ManyToOne attribute.
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
@ManyToOne
@JoinColumn(name="BLOODGRUPID")
@Cascade({CascadeType.MERGE, CascadeType.SAVE_UPDATE})
private Bloodgroup bloodgroup;
Upvotes: 1
Reputation: 3874
I had a similar problem and although I made sure that referenced entities were saved first it keeps failing with the same exception. After hours of investigation it turns out that the problem was because the "version" column of the referenced entity was NULL. In my particular setup i was inserting it first in an HSQLDB(that was a unit test) a row like that:
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);
The problem of the above is the version column used by hibernate was set to null, so even if the object was correctly saved, Hibernate considered it as unsaved. When making sure the version had a NON-NULL(1 in this case) value the exception disappeared and everything worked fine.
I am putting it here in case someone else had the same problem, since this took me a long time to figure this out and the solution is completely different than the above.
Upvotes: 13
Reputation: 11113
your issue will be resolved by properly defining cascading depedencies or by saving the referenced entities before saving the entity that references. Defining cascading is really tricky to get right because of all the subtle variations in how they are used.
Here is how you can define 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;
}
In this scenario, every time you save, update, delete, etc Userrole, the assocaited Role and User will also be saved, updated...
Again, if your use case demands that you do not modify User or Role when updating Userrole, then simply save User or Role before modifying Userrole
Additionally, bidirectional relationships have a one-way ownership. In this case, User owns Bloodgroup. Therefore, cascades will only proceed from User -> Bloodgroup. Again, you need to save User into the database (attach it or make it non-transient) in order to associate it with Bloodgroup.
Upvotes: 42