My New Project is in Hibernate 4.2.5.Final and Spring. After Login, I am storing the user object in the session. Now after successful login, I need to insert one record in the application log. Here are the classes:
Class BaseEntity
@MappedSuperclass
public abstract class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long ID;
@Version
private Long version;
private Long createdBy;
@Temporal(value = TemporalType.TIMESTAMP)
private Date createdDate;
private Long updatedBy;
@Temporal(value = TemporalType.TIMESTAMP)
private Date updatedDate;
private String deactivatedReason;
private String activatedReason;
private Integer active;
public long getID() {
return ID;
}
public void setID(long iD) {
ID = iD;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
public Long getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Long createdBy) {
this.createdBy = createdBy;
}
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
public Long getUpdatedBy() {
return updatedBy;
}
public void setUpdatedBy(Long updatedBy) {
this.updatedBy = updatedBy;
}
public Date getUpdatedDate() {
return updatedDate;
}
public void setUpdatedDate(Date updatedDate) {
this.updatedDate = updatedDate;
}
public String getDeactivatedReason() {
return deactivatedReason;
}
public void setDeactivatedReason(String deactivatedReason) {
this.deactivatedReason = deactivatedReason;
}
public String getActivatedReason() {
return activatedReason;
}
public void setActivatedReason(String activatedReason) {
this.activatedReason = activatedReason;
}
public Integer getActive() {
return active;
}
public void setActive(Integer active) {
this.active = active;
}
}
Class Users:
package com.product.domain;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;
import com.product.audit.IAuditLog;
import com.product.domain.base.BaseEntity;
@Entity
@Table(name = "users")
@NamedQueries({ @NamedQuery(name = "Users.findUserByUserID", query = "SELECT usr FROM Users as usr WHERE usr.userName = ? and usr.practice.code = ?") })
public class Users extends BaseEntity implements IAuditLog {
private String userName;
private String password;
// bi-directional many-to-one association to Practice
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "practiceID")
private Practice practice;
//getters and setters
}
Class ApplicationEvents:
package com.product.domain;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity
@Table(name = "applicationevents")
public class ApplicationEvents {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long ID;
@Temporal(value = TemporalType.TIMESTAMP)
private Date eventDate;
private String comments;
private Integer eventType;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "practiceID")
private Practice practice;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userID")
private Users userID;
//getters and setters
}
ApplicationEvents appEvent = new ApplicationEvents();
appEvent.setEventType(eventType);
appEvent.setPractice(practice);
appEvent.setUserID(userID);
appEvent.setComments(comments);
appEvent.setEventDate(new Timestamp(new Date().getTime()));
CRUDService.Save(appEvent);
When I try to save ApplicationEvent, I am getting the following error:
18:34:34.540 [http-bio-8080-exec-8] INFO c.p.a.MyUserDetailsService - Logged User authentication sucess. UserName admin and practice Name Physicians Choice Laboratory
Hibernate:
/* insert com.product.domain.ApplicationEvents
*/ insert
into
applicationevents
(comments, eventDate, eventType, practiceID, userID)
values
(?, ?, ?, ?, ?)
19 Sep, 2013 6:34:34 PM org.zkoss.bind.impl.ParamCall call:117
SEVERE:
org.springframework.dao.InvalidDataAccessApiUsageException: object references an unsaved transient instance - save the transient instance before flushing: com.product.domain.Users; nested exception is org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.product.domain.Users
at org.springframework.orm.hibernate4.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:166)
at org.springframework.orm.hibernate4.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:680)
at org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:562)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:755)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:475)
Very Important Note: When I remove the @Version in the base entity, everything works fine.
Users
object come from exactly? If you are pulling the User from the session, at that moment in time it is detached from the persistence context and considered transient. See Persistence Contexts. You would need to do amerge
orsaveOrUpdate
on theUsers
object to re-attach it to the persistence context as @Prabhakaran suggests. – JaffaUsers
object is transient if it is being pulled from the session, not detached. Detached objects are slightly different than transient objects Working with objects. – Jaffa@Version
annotation is meant to prevent exactly what you are worried about. If there was a concurrent modification of theUsers
object it will throw an exception during flush Optimistic concurrency control. As to why you don't get an exception if you remove@Version
... it's probably because hibernate is not doing a version check in that case and therefore goes back to 'last-commit-wins' mode. – Jaffa