# JPA Verständnisproblem - persist(), merge(), getReference()



## mephi (5. Dez 2008)

Ich check gerade nicht ganz wie ich ein eigentlich simples Problem lösen soll..

Ich bekomm in meinem Servlet eine userId. So nun stellt sich die Frage ob es den User in der DB schon gibt oder nicht. getReference liefert ja leider nicht null zurück sondern wirft eine Exception wenn es den User nicht gibt. Ich könnte einfach ein neues User Objekt anlegen, aber dann muss ich wieder unterscheiden ob ich merge() aufrufe falls es den User schon gibt bzw nichts wenn sich nichts an ihm verändert oder persist() ..
Rufe ich nur merge() auf under User war noch nicht in der DB vorhanden, gibts spätestens Probleme wenn ich den User bei einem neuen Session objekt mit setUser() übergebe und die Session per persist() speichern will. Dann kommt die Fehlermeldung: "not-null property references a null or transient value:"

Irgendwie check ich nicht wie ich damit arbeiten soll. Das sind ja bisher nur einfache Tests die ich irgendwie hinbiegen kann. Aber ich weiß nicht wie ich eine fehlerfreie Anwendung schreiben soll.

Oder muss ich immer Queries starten um zu schauen was existiert? Dachte genau das nimmt mir ein Persistenz Framework ab


----------



## byte (5. Dez 2008)

mephi hat gesagt.:
			
		

> getReference liefert ja leider nicht null zurück sondern wirft eine Exception wenn es den User nicht gibt.


Und wo genau liegt das Problem, die Exception zu fangen und dann das Objekt neu anzulegen?
Ich benutze den EntityManager nicht sondern arbeite direkt mit der Hibernate Session (bzw. HibernateTemplate in Spring). Dort gibts ne Methode saveOrUpdate(), die entweder das Objekt updated oder - falls es noch nicht existiert - das Objekt anlegt.


----------



## maki (5. Dez 2008)

Warum nicht die find Methode nutzen?

Genau dafür ist sie ja schliesslich da.


----------



## mephi (5. Dez 2008)

byto hat gesagt.:
			
		

> mephi hat gesagt.:
> 
> 
> 
> ...



wie im anderen thread mal erwähnt möchte ich da ja variabel sein und mich noch nicht auf ein framework festlegen



			
				maki hat gesagt.:
			
		

> Warum nicht die find Methode nutzen?
> 
> Genau dafür ist sie ja schliesslich da.



danke, die methode hab ich natürlich gekonnt übersehen :roll:  


*edit*
wenn ich den thread schon offen hab:

wir würdet ihr folgendes lösen?

ich hab ein event objekt mit werten wie eventype, payload usw. diese felder zusammen sind unique. aber um es einfacher zu handeln würde ich gern eine automatische id vergeben die dann auch der PK ist. wenn nun die daten für ein event reinkommen(also type,payload etc) möcht ich die referenz für diesen event haben und keinen neuen anlegen(was ja auch nicht geht). hab mir überlegt die 4 felder zum PK zu machen und die ID einfach nur unique, oder wäre das eher ungeschickt?


----------



## byte (5. Dez 2008)

Composite Keys sind gruselig, würde ich auf keinen Fall machen. PK sollte immer ein Kunstschlüssel sein!

Mach doch einfach ein @UniqueConstraint auf die entsprechenden Spalten.


----------



## mephi (5. Dez 2008)

Das habe ich gemacht. Aber in meinem Servlet bekomm ich nur die Daten des Events und nicht den Key dazu. Hier müsste ich dann per Query mit den Daten die Id des Events holen oder ihn gegebenfalls neuanlegen? Oder gibts hier eine andere Möglichkeit die direkt vom Framework angeboten wird?


----------



## byte (5. Dez 2008)

Die ID holen? Du meinst die Entity holen!? Ja, Du musst dann mit den Werten dann das Objekt per Query holen. Um Queries kommst Du auch bei ORMs selten herum. Aber mit den richtigen UniqueConstraints auf einem Table ist das Query sehr schnell.


----------



## mephi (5. Dez 2008)

Ja die Entity natürlich 
Das schreit ja dann nach einer @NamedQuery

danke


----------



## byte (5. Dez 2008)

Oder halt einfach eine Methode im entsprechenden DAO.


----------



## maki (5. Dez 2008)

Oder beidem


----------



## mephi (5. Dez 2008)

ein extra DAO hab ich nicht. ich hab einfach alle annotations in meine POJOs rein


----------



## byte (5. Dez 2008)

Naja, irgendwo machst Du ja mit dem PersistenceManager Deine DB-Operationen, um Deine POJOs zu laden und zu speichern. Für gewöhnlich schreibt man sich eine DAO Schicht für diese Zwecke. Wo machst Du denn diese Aufrufe derzeit? Direkt im Servlet? Davon ist abzuraten.


----------



## mephi (7. Dez 2008)

Ich hab eine "System" Klasse als Threadlocal implementiert, da gibts Methoden wie "loadEvent" und "saveEvent". Ich hab mir überlegt in diesen Methoden direkt gleichnamige Methoden im PersistenceManager aufzurufen wo ich dann die DB operationen mit dem EnitityManager mache. So wäre die Schicht komplett getrennt.


----------



## mephi (9. Dez 2008)

So ich nutz den Thread weiter 

Bei einer ManyToOne Beziehung in der einen Klasse und eine OneToMany Beziehung in der anderen..


```
@OneToMany(targetEntity=SessionImpl.class, mappedBy="user")
	private List<ISession> sessionList = new ArrayList<ISession>();
```


```
@ManyToOne(targetEntity=UserImpl.class)
	@JoinColumn(nullable=false)
	private IUser user;
```

wenn ich nun in der session den user setze, dann ist er nicht automatisch auch in der sessionList vom user.
wie gehe ich da nun vor? von hand die session beim user adden oder muss ich meine transaction erstmal committen und dann den user neuladen??
irgendwie ist mir die ganze vorgehensweise noch etwas unverständlich


----------



## maki (9. Dez 2008)

Bi-direktionale Beziehungen sind komplexer als Uni-direktionale, die Mapping annos beziehen sich darauf, was passiert, wenn die Objekte aus der DB geladen/gespeichert werden, nicht darauf was passiert wenn du Zuweisungen an die Objekte machst.
Mit anderen Worten: 


> von hand die session beim user adden


Ja, so etwas muss man "von hand" machen, denn das ist nicht worum es bei JPA geht 

Bi-direktionale Assos haben ihren Preis, am besten eines der Objekte kümmert sich darum, das beides gesetzt wird.

Gehören Sessions eigentlich zu deiner Domäne?


----------



## mephi (9. Dez 2008)

In dem Fall schon. Die übernehm ich einfach vom request und die dient in dem Fall als Gruppierung von Events. Könnt ich auch über die Zeit machen, aber das Design hab ich nicht allein aufgestellt


----------

