Java – hibernate saveorupdate() attempts to save when it should be updated
I have a hibernate entity named issueparticipant It basically describes the relationship between users and problems (similar to JIRA or bugzilla problems) It represents a many to many linked table in the database, which links the user ID to the problem ID, but also includes other information related to notification settings, so it is regarded as its own entity
I encountered a big problem when using userid and issueid as composite keys, so I created a composite key, which is a string (and varchar in Postgres database), which is formed as follows:
Now, I have a screen where users can edit all users related to the problem and edit notification settings In the controller class, I create an issueparticipants list as follows:
IssueParticipant participant = new IssueParticipant(); participant.setUser(accountUser); participant.setIssue(issue);
So of course these are not managed by hibernate
Then in my Dao, I iterate over them and call saveOrUpdate (), expecting that if there is an issueparticipant with the same composite key in the database, it will be updated; Otherwise it will be inserted:
for (IssueParticipant participant : participants) { getCurrentSession().saveOrUpdate(participant); savedIds.add(participant.getIssueUserKey()); }
(savedids is the list I'm maintaining so that later I'll know which issuepaarticipants I should delete from the database)
Instead of what I expected, I got an exception:
org.postgresql.util.PsqlException: ERROR: duplicate key value violates unique constraint "issue_participant_pkey"
This is my entity class, abbreviated as:
public class IssueParticipant extends Entity { private String issueUserKey; private Long issueId; private Long userId; // Edit: adding 'dateAdded' deFinition private Date dateAdded; // ... // below may be null private SPUser user; private Issue issue; public static IssueParticipant nulledIssueParticipant() { IssueParticipant ip = new IssueParticipant(); return ip; } public String getIssueUserKey() { return issueUserKey; } public void setIssueUserKey(String issueUserKey) { this.issueUserKey = issueUserKey; } public Long getId() { // currently meaningless return 0L; } public Long getIssueId() { return this.issueId; } public void setIssueId(Long issueId) { this.issueId = issueId; updateKey(); } public Long getUserId() { return this.userId; } public void setUserId(Long userId) { this.userId = userId; updateKey(); } private void updateKey() { issueUserKey = getIssueId() + KEY_SEP + getUserId(); } public SPUser getUser() { return user; } public void setUser(SPUser user) { this.user = user; setUserId(user.getId()); } public Issue getIssue() { return issue; } public void setIssue(Issue issue) { this.issue = issue; setIssueId(issue.getId()); } // edit: adding 'dateAdded' methods public Date getDateAdded() { return dateAdded; } public void setDateAdded(Date dateAdded) { this.dateAdded = dateAdded; } ... }
This is its HBM file:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping default-lazy="false"> <class name="com.xxx.yyy.IssueParticipant" table="issue_participant"> <id name="issueUserKey" column="issue_user_key" type="string"> <generator class="assigned"/> </id> <version name="dateAdded" column="date_added" type="timestamp" unsaved-value="null" /> <property name="issueId" column="issue_id" /> <many-to-one name="user" column="user_id" class="com.xxx.yyy.SPUser" not-null="true" cascade="none" /> <property name="alertRSS" column="alert_RSS" type="boolean" /> <property name="alertEmail" column="alert_email" type="boolean" /> <property name="alertWeb" column="alert_web" type="boolean" /> <property name="alertClient" column="alert_client" type="boolean" /> </class> </hibernate-mapping>
Actually, user_ issue_ Key is the primary key in the corresponding database table
In this case, I think the correct solution may be to use spring JDBC, but I really want to know what happened here What does anyone think? Thank you in advance
Solution
Saveorupdate() does not query the database to determine whether a given entity should be saved or updated It makes decisions based on the status of the entity as follows:
Therefore, as far as I know, in your case, the decision is based on the value of the dateadded field, so you need to keep it to distinguish between new instances and separated instances
You can also see:
> 11.7. Automatic state detection