Java – hibernate merge lost data
I had a strange problem with hibernate and merging
The structure of the problematic class is as follows:
Project --> CaseWorkerA --|> CaseWorker --|> User
So basically, I have a project class that contains a reference to caseworker a, which is a subclass of caseworker and a subclass of user
In the code:
public class Project { [...] private CaseWorkerA caseWorkerA; @ManyToOne(fetch = FetchType.EAGER) @Cascade({ org.hibernate.annotations.CascadeType.SAVE_UPDATE,org.hibernate.annotations.CascadeType.PERSIST,org.hibernate.annotations.CascadeType.REFRESH,org.hibernate.annotations.CascadeType.MERGE }) @JoinColumn(name = "CaseWorker_A") public CaseWorkerA getCaseWorkerA() { return caseWorkerA; } }
Then we have user hierarchy:
public class User { [...] } public class CaseWorker extends User { private CaseWorkerStatus status; @Enumerated(EnumType.STRING) public CaseWorkerStatus getStatus() { return status; } [...] } public class CaseWorkerA extends CaseWorker { [...] }
Then, there is a method in the Dao class to store the project:
public class ProjectDao { [...] public Project saveUpdateProject(final Project project) { if (project.getId() == null) { getSession(false).save(project); } else { project = (Project) getSession(false).merge(project); } getHibernateTemplate().flush(); return project; } }
Now, the question is as follows:
The Dao method receives items that exist in the database This project is connected to caseworkera and its status is caseworkerstatus Active (in database and incomming objects) But after the merger, the status of the case worker becomes empty
I really don't understand how this is possible, because the values in the database are the same, just like the objects to be stored. I want it to remain unchanged after merging
(there are no triggers in the database for this field..)
(I'll try to change Dao method to use saveOrUpdate, but even if this will solve the problem, I'm still curious to know what's causing it.)
to update:
So I fiddled with the debugger and found the following: when I queried the problematic caseworker's session, it appeared its state field set (in fact, the returned object is the object connected to project)
Execute saveOrUpdate and then get, causing caseworker to set status field So it seems to be a problem with the merge method
Solution
Manage well and understand. It turns out that there is a second path from the project to the user (last changed by, something similar). Someone decides to put it into the cascade for some strange reason Therefore, when the person who last changed the project is caseworker, lastchangedby refers to it as user. It does not know the status, so it is stored as null
Code:
public class Project { private User changedBy; @Cascade({ org.hibernate.annotations.CascadeType.SAVE_UPDATE,org.hibernate.annotations.CascadeType.MERGE }) @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "changed_by") public User getChangedBy() { return this.changedBy; } [...] }
The user set to changedby retrieves the following from the database:
public class UserDao { public User getUser(final String userName) { return (User) getSession(false).createQuery("from User u where u.loginName = :username").setParameter("username",userName).uniqueResult(); } }
Obviously, even if the final retrieved user is a caseworker, the fields related to caseworker will not be retrieved
In any case, the unsuccessful cascade is deleted, which is all good:)