Hibernate saveOrUpdate() versucht zu speichern, wenn Sie es aktualisieren sollten
Ich habe eine Hibernate-Entität namens IssueParticipant. Es ist im Grunde beschreibt die Beziehung zwischen einem Benutzer und einem Problem (und das ist wie ein JIRA oder Bugzilla Problem). Es stellt eine Art von viele-zu-viele-Verknüpfung Tabelle in der Datenbank, die Verknüpfung Benutzer-ID, um eine Problem-ID, aber es enthält auch andere Informationen in Bezug auf Benachrichtigungs-Einstellungen, und so wird es behandelt, als eigene Entität.
Ich hatte riesige Probleme bei der Verwendung der userId und issueId als einen zusammengesetzten Schlüssel, so habe ich einen Klebeprozess der key ist ein String (und varchar in die postgres-Datenbank), die gebildet ist: _.
Nun, ich habe einen Bildschirm, auf dem ein Benutzer Bearbeiten können alle Benutzer im Zusammenhang mit einem Problem, während auch das Bearbeiten der Benachrichtigungseinstellungen. In einer controller-Klasse die ich erstellen Sie eine Liste der IssueParticipants wie diese:
IssueParticipant participant = new IssueParticipant();
participant.setUser(accountUser);
participant.setIssue(issue);
So sind diese natürlich nicht geschafft, die von Hibernate an dieser Stelle.
Dann in meinem DAO ich Durchlaufen Sie, und rufen Sie saveOrUpdate(), in der Erwartung, dass, wenn ein IssueParticipant mit dem gleichen synthetischen Schlüssel in der Datenbank vorhanden, wird es aktualisiert, ansonsten wird eingefügt:
for (IssueParticipant participant : participants) {
getCurrentSession().saveOrUpdate(participant);
savedIds.add(participant.getIssueUserKey());
}
(savedIds ist eine Liste, die ich bin Pflege, so dass ich später wissen, was IssueParticipants ich sollte aus der Datenbank löschen).
Statt, was ich erwarte, wenn ich eine Ausnahme:
org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "issue_participant_pkey"
Hier ist meine entity-Klasse, abgekürzt:
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;
}
...
}
Hier ist Ihre hbm-Datei:
<?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>
Und in der Tat user_issue_key
ist der Primärschlüssel in der entsprechenden Datenbank-Tabelle.
Fühle ich mich wie die richtige Lösung könnte nur sein, zu verwenden SpringJDBC
in diesem Fall, aber ich möchte wirklich gerne herausfinden, was hier Los ist. Jemand irgendwelche Gedanken? Vielen Dank im Voraus.
Du musst angemeldet sein, um einen Kommentar abzugeben.
saveOrUpdate()
nicht die Abfrage der Datenbank zu entscheiden, ob es speichern soll oder aktualisieren Sie den gegebenen Entität. Es macht, dass die Entscheidung auf der Grundlage des Status des Unternehmens, wie folgt:Also, soweit ich verstehe in Ihrem Fall die Entscheidung basiert auf dem Wert der
dateAdded
Feld, deshalb Sie brauchen, um es zu unterscheiden zwischen neuen und getrennten Instanzen.Siehe auch:
Können Sie es, um die Datenbank abzufragen um diese Feststellung zu machen, wenn Sie es wirklich wollen. Ändern Sie Ihre id-mapping:
In der Regel, dass ist nicht der beste Weg aber. Sie haben in der Tat eine
<version/>
mapping ist in der Regel eine bessere fallback-aus der Kennung für die Entscheidung zwischen speichern/aktualisieren, ohne den Aufwand der Abfragen der Datenbank. Sie habe versucht, es zuunsaved-value="null"
. Aber Sie haben nicht die Eigenschaft mapping für Ihre IssueParticipant.dateAdded Eigenschaft (das ist, was Sie versuchen, Karte, wie<version/>
; Sie erkennen die version wird erhöht, jedes update oder?; auch müssen Sie wissen, über<timestamp/>
statt<version/>
richtig?). Eh, das ist, wo dein problem ist. Könnten Sie zeigen die definition der IssueParticipant.dateAdded Eigenschaft?