[JPA] Best Practise für Sonderfall

y0dA

Top Contributor
Vorweg ich benutze EJB, JPA, OpenJPA, WS7 --> dürfte aber alles keine Rolle spielen ausser vllt die "alte" openjpa Version 1.2.3

Die Problemstellung:
Ich habe eine Entität "Objekt" welche verschiedene Status Stadien durchlebt (beantragt, ausgestellt, abgewiesen, genehmigt,..) und selbiges sollte eigentlich wie folgt abgebildet werden:

1 Objekt hat viele Status
1 Status gehört zu einem Objekt
--> Objekt 1:n Status
= somit müsste ich in der Entität Objekt eine Liste von Status anbieten, aus programmatischer Sicht aber nicht schön gelöst (für meine Fall) da ich nämlich so gut wie immer mit dem aktuellen Status arbeiten muss, ist auf Java Ebene nicht unbedingt ein Problem jedoch wenn ich eine named query auf den aktuellen Status prüfen möchte gestaltet sich das schon komplizierter als es eigentlich sein sollte.

Deshalb habe ich folgendes abgebildet:
Entitäten:
Java:
public class Objekt {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;

	@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH })
	@JoinColumn(name = "status", nullable = true)
	private Status aktuellerStatus;
..
}
Java:
public class Status {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;

	@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
	@JoinColumn(name = "objekt", nullable = false)
	private Objekt objekt;
..

Selbiges funktioniert lustigerweise auch sofern ich ein insert mache (sprich Objekt wird das erste Mal persistiert mit dem Status "beantragt"). Wenn ich nun jedoch eine Statusänderung durchführe (bspw. auf "ausgestellt") dann klappt hierbei auch das Update con Objket sowie das Insert in die Tabelle Status jedoch bekomme ich im Result die ID nicht mit (selbige ist bspw. nachdem Insert oder beim Laden des Objekts vorhanden).

Hatte jemand eine ähnliche Sachlage und kann mir sagen wie ich diese Problematik anders (besser) lösen kann oder eine Lösung weiß warum die ID nicht mit zurückgegeben wird?
 
Zuletzt bearbeitet:

AndyHa

Mitglied
Hallo y0dA,

es mag an der späten Uhrzeit liegen, aber deine Beschreibung leuchtet mir nicht ganz ein. Kann dein Objekt nicht zu jedem Zeitpunkt immer nur höchstens einen Zustand haben, den du aus einer Menge von Status auswählen kannst? Umgekehrt kann aber jeder Status bei unterschiedlichen Objekten mehrfach auftreten.
Somit müsstest du folgende Annotationen verwenden:

Java:
@ManyToOne(optional=true)
private Status aktuellerStatus;

bzw.
Java:
@OneToMany(mappedBy=aktuellerStatus)
private Collection<Objekt> objekt;

Falls das deinem Problem nicht gerecht wird, kannst es vielleicht noch einmal präzisieren.

Viele Grüße
Andy
 

y0dA

Top Contributor
Danke für deine Antwort aber du hast mein Problem tatsächlich mißverstanden. Das was ich am liebsten hätte ich wohl nicht korrekt darstellbar mittels JPA.

1 Objekt hat n Status jedoch soll im Objekt nur der aktuelle Status referenziert werden(das bedeutet jedes Objekt hat seine eigenen Status - Status sind keine Stammdaten, es muss auch eine Art Historie der Statusänderungen dargestellt werden!). Sprich das Objekt wird das erste Mal persistiert und bekommt den aktuellen Status "beantragt". Das bedeutet in der Tabelle Status gibt es nun einen Eintrag "beantragt" mit Datum des Status und einer Referenz auf das Objekt für welches der Status angelegt wurde. Danach kommt es zu einem Statuswechsel, das bedeutet einen neuen Eintrag in der Tabelle Status, bspw. "ausgestellt" und hierbei soll dann im Objekt im Feld "aktuellerStatus" nur auf das Objekt "ausgestellt" referenziert sein.

Meine Idee entspricht wohl nicht der dritten Normalform :)
 
Zuletzt bearbeitet:

AndyHa

Mitglied
Gut, dann vergiss, was ich gestern geschrieben habe ;-)

Du willst also im Grunde drei Informationen für ein Objekt speichern:
1. eine Liste der Status, die das Objekt annehmen kann; hier solltest du dann per @OneToMany die Liste speichern, die auf die Status-Entität verweist (bzw. @ManyToMany, falls ein Status auch für verschiedene Objekte möglich ist).
2. den aktuellen Zustand des Objekts; das kannst du ja wie gehabt mit @ManyToOne-Annotation verwenden.
3. für die Historisierung alter Zustände verwende ich Envers, das ist jedoch eine Erweiterung von Hibernate, also einer anderen JPA-Implementierung als die, die du verwendest. Vielleicht gibt es etwas Analoges auch bei OpenJPA.

Viele Grüße
Andy
 

brauner1990

Bekanntes Mitglied
Also was hälst du davon dies bei Änderung der Status in eine Map zu speichern. Also Sozusagen
Code:
Hashmap<java.util.Date,Status> history=new Hashmap<java.util.Date,Status>()
.
 

y0dA

Top Contributor
Danke für die Vorschläge. Dachte eigentlich dass, so wie ich es gemacht habe, es nicht funktionieren sollte da es hierbei nämlich ein Problem gibt. Wenn ich naemlich nun Objekt mit einem neuen Status persistiere (merge) dann wird beim "aktuellerStatus" die ID nicht gesetzt. Dachte dass das aufgrund meines komischen @ManyToOne @ManyToOne passiert - eventuell hat OpenJPA hier auch eine Bug :(. Sehe grade dass ich diesen Sachverhalt bei meinem Eingangspost eh erwähnt hatte.

Ich habe kein Problem mit "Historisierung" etc., es besteht ausschließlich ein Problem mit "aktuellerStatus" wenn jenes Feld in Objekt neu gesetzt wird, dann wird ein Merge auf Objekt durchgeführt und hierbei der neue Status auch in die Tabelle Status persistiert (mit etwaigen anderen notwendigen Feldern).
 

brauner1990

Bekanntes Mitglied
Ich weiß ja nicht wie deine Controller aufgebaut sind, aber hier müsstest du dann doch sozusagen zwischen "create" und "edit" unterscheiden nicht oder?
 

Ähnliche Java Themen


Oben