In my teamwork oriented app I have many-to-many relationship between User and Team, so hibernate creates association table. Problem is, that after updating the User which has Team, hibernate deletes corresponding association record from USER_TEAM table.
User entity:
@Entity
@Table(name="USERS")
public class User extends SelectItem {
@Id
@Column(name="EMAIL")
private String email;
@Column(name="PASSWORD")
private String password;
@Column(name="NAME")
private String name;
@Column(name="GROUPNAME")
private String group;
@ManyToMany(
targetEntity=Team.class
)
@ForeignKey(name="FK_TEAM_TO_USER", inverseName = "FK_USER_TO_TEAM")
@JoinTable(
name="USER_TEAM",
joinColumns=@JoinColumn(name="EMAIL"),
inverseJoinColumns=@JoinColumn(name="TEAMNAME")
)
@LazyCollection(LazyCollectionOption.FALSE)
private List<Team> teamList;
@OneToMany(
fetch = FetchType.EAGER,
mappedBy="user")
private List<Invitation> invitationList;
//getters setters
Team entity:
@Entity
@Table(name="TEAM")
public class Team extends SelectItem {
@Id
@Column(name="TEAMNAME")
private String name;
@ManyToOne
@ForeignKey(name="FK_TEAM_TO_TEAMLEADER")
@JoinColumn(name="TEAMLEADER")
private User teamLeader;
@ManyToMany(
mappedBy = "teamList",
targetEntity = User.class
)
@LazyCollection(LazyCollectionOption.FALSE)
private List<User> memberList;
//getters setters
Here is the log:
INFO: 20.11.2012 22:50:00,170 DEBUG org.hibernate.transaction.JDBCTransaction.begin: begin
INFO: 20.11.2012 22:50:00,175 DEBUG org.hibernate.transaction.JDBCTransaction.begin: current autocommit status: true
INFO: 20.11.2012 22:50:00,175 DEBUG org.hibernate.transaction.JDBCTransaction.begin: disabling autocommit
INFO: 20.11.2012 22:50:00,175 DEBUG hibernate.jdbc.util.SQLStatementLogger.logStatement: select user_.EMAIL, user_.GROUPNAME as GROUPNAME0_, user_.NAME as NAME0_, user_.PASSWORD as PASSWORD0_ from USERS user_ where user_.EMAIL=?
INFO: Hibernate: select user_.EMAIL, user_.GROUPNAME as GROUPNAME0_, user_.NAME as NAME0_, user_.PASSWORD as PASSWORD0_ from USERS user_ where user_.EMAIL=?
INFO: 20.11.2012 22:50:00,176 TRACE type.descriptor.sql.BasicBinder.bind: binding parameter [1] as [VARCHAR] - a@b.com
INFO: 20.11.2012 22:50:00,177 TRACE type.descriptor.sql.BasicExtractor.extract: found [users] as column [GROUPNAME0_]
INFO: 20.11.2012 22:50:00,178 TRACE type.descriptor.sql.BasicExtractor.extract: found [default] as column [NAME0_]
INFO: 20.11.2012 22:50:00,178 TRACE type.descriptor.sql.BasicExtractor.extract: found [default] as column [PASSWORD0_]
INFO: 20.11.2012 22:50:00,251 DEBUG org.hibernate.transaction.JDBCTransaction.commit: commit
INFO: 20.11.2012 22:50:00,252 DEBUG hibernate.jdbc.util.SQLStatementLogger.logStatement: update USERS set GROUPNAME=?, NAME=?, PASSWORD=? where EMAIL=?
INFO: Hibernate: update USERS set GROUPNAME=?, NAME=?, PASSWORD=? where EMAIL=?
INFO: 20.11.2012 22:50:00,260 TRACE type.descriptor.sql.BasicBinder.bind: binding parameter [1] as [VARCHAR] - users
INFO: 20.11.2012 22:50:00,261 TRACE type.descriptor.sql.BasicBinder.bind: binding parameter [2] as [VARCHAR] - andy
INFO: 20.11.2012 22:50:00,261 TRACE type.descriptor.sql.BasicBinder.bind: binding parameter [3] as [VARCHAR] - break
INFO: 20.11.2012 22:50:00,262 TRACE type.descriptor.sql.BasicBinder.bind: binding parameter [4] as [VARCHAR] - a@b.com
INFO: 20.11.2012 22:50:00,264 DEBUG hibernate.jdbc.util.SQLStatementLogger.logStatement: delete from USER_TEAM where EMAIL=?
INFO: Hibernate: delete from USER_TEAM where EMAIL=?
INFO: 20.11.2012 22:50:00,271 TRACE type.descriptor.sql.BasicBinder.bind: binding parameter [1] as [VARCHAR] - a@b.com
INFO: 20.11.2012 22:50:00,274 DEBUG
org.hibernate.transaction.JDBCTransaction.toggleAutoCommit: re-enabling autocommit INFO: 20.11.2012 22:50:00,274 DEBUG org.hibernate.transaction.JDBCTransaction.commit: committed JDBC Connection
The update operation is provided by spring's hibernateTemplate in this simple method in UserDAO:
public void saveUser(User user){
hibernateTemplate.saveOrUpdate(user);
}
(I know that hibernateTemplate shouldn't be used, but I think that's not the point in this problem)
And DAO method is simply called in transaction by spring service bean UserServiceImpl:
@Transactional(readOnly=false)
public void saveUser(User user){
userDao.saveUser(user);
}
As you can see, I don't have any cascade annotations and in update I don't change PK of User (EMAIL) of course, so I don't understand this behaviour. I'm using spring 3.1.0.RELEASE and hibernate 3.6.10.Final.
Thanks for any suggestions or explanations.
You don't need any cascade for this to happen. The contents of the join table for a given user is determined by the contents of the teamList
collection of this user. So if you call saveOrUpdate()
with a User that has an empty team list, Hibernate will remove the contents of the join table for this user.