# Hibernate: save, update, saveOrUpdate, merge, .... [an alle Hibernate-Profis]



## DerGrinsemann (11. Juni 2007)

Hallo!

Mein Gehirn nähert sich einem geistigen Kurzschluss, seit Tagen brüte ich über folgendes Szenario und ich komme einfach nicht weiter:

Frameworks:
- Spring-Framework 2.x
- Hibernate 3.x

Aufbau:
Controller - Service - DAO - Domain

Auf allgemeines Anraten (Bücher, Forum usw)  reiche ich meine Domain-Objekte durch alle Schichten durch und verzichte auf DTO's.

In meinem Übungsbeispiel arbeite ich mit den Domain-Objekt Person.

Benutzer 1:

wählt einen Eintrag (Person) zur Bearbeitung aus (SimpleFormController, formBackingObject gibt das Domain-Objekt zurück)
Der Benutzer ändert etwas (z.B. Vorname) oder auch gar nix
Somit lande ich im SimpleFormController, onSubmit und konventiere wieder in "Person person = (Person) object;"
Jetzt habe ich ein Domain-Objekt person das Detached ist

Benutzer 2 (in der Zwischenzeit):

löscht den selbigen Eintrag (diese Person war ihn immer schon unsympathisch ;-) )
Somit ist dieses Domain-Objekt person also Transient

Was mache ich jetzt mit Benutzer 1?


update: geht nicht (führt IMMER ein update aus, auch wenn keine Änderungen stattgefunden haben und erhöht mir meinen version-Zähler (optimistische Sperre), bzw. existiert das Objekt ja auch nicht mehr in der DB)
save: geht nicht (da Benutzer 1 nichts von der Löschung weiss)
saveOrUpdate, merge:  geht nicht (wäre zwar OK für Benutzer 1, aber für Benutzer 2 taucht der gerade gelöschte Datensatz wieder auf)
get, update: sehr umständlich, ich hole mir mittels get und der ID das selbe Objekt (somit Persistent) oder erhalte null und kann darauf reagieren. Kopiere alle Eigenschaften vom Detached-Objekt in das Persitent-Objekt um und mache ein update auf das Persistent-Objekt. Das wäre übrigends das DTO-Pattern.

Wo ist mein Knoten, meine Blockade, ... ?

Oder anders gefragt: Wie bringe ich vernünftig ein Domain-Objekt mit den Status "detached" in den Status "persitent"?

Marco


----------



## zerix (13. Juni 2007)

Hallo,

also wenn ich dich richtig verstanden habe, benutzt jeder User die gleiche Datenbank mit den gleichen Tabellen. Meiner Meinung nach ist es in dieser Situation gar nicht möglich ein Object abzuspeichern ohne dass es von einem anderen Nutzer gesehen wird.
Eine Idee von mir wäre, damit es nicht mit zu großen Änderungen verbunden wäre, dass du eine allgemeine Tabelle hast mit allen Daten zu den Personen und dann eine Tabelle für jeden Nutzer in der nur die Primary-Keys der Personen stehen, die bei ihm angezeigt werden sollen.
Ich hoffe ich konnte dir etwas helfen.

MFG

zEriX


----------



## DerGrinsemann (13. Juni 2007)

Hallo!

Ich dürfte die Antwort auf mein Problem gefunden haben! Leider!

In der EJB-Spezifikation 3.0 steht folgendes zu "merge"


```
/** 
 * Merge the state of the given entity into the 
 * current persistence context. 
 * @param entity 
 * @return the instance that the state was merged to 
 * @throws IllegalArgumentException if instance is not an 
 *                 entity or is a removed entity 
 * @throws TransactionRequiredException if invoked on a 
 * container-managed entity manager of type 
 * PersistenceContextType.TRANSACTION and there is 
 * no transaction. 
 */ 
public <T> T merge(T entity);
```

Genau das würde mein Problem beheben!

Der Request von Benutzer 1 möchte ein Objekt mit den Status "Detached" in den Status "Persistent" überführen, was aber nicht geht, da Benutzer 2 genau dieses Objekt aus der Datenbank gelöscht hat.

*ABER !!*

Das "merge" von Hibernate 3.x verhält sich nicht so - sondern führt dann einfach ein "insert" auf der DB aus. Somit entspricht dieses "merge" einem "saveOrUpdate".

Und das entspricht meines Erachtens nicht der EJB Spezifikation 3.0 ... was ist eure Meinung?

Marco

P.S.: Es gibt einen Eintrag im Bug-Tracking von Hibernate unter

http://opensource.atlassian.com/projects/hibernate/browse/HHH-1661

vom April 2006.


----------

