Mittwoch, 14. März 2012

JPA2 Feature Speichern der Reihenfolge von Elementen einer Assoziation

Es gibt nun mit JPA 2 ein neues Feature mit dem man bei einer Assoziation die Reihenfolge der Elemente
sicherstellen kann, d.h. die Reihenfolge der Elemente einer Assoziation, die als Liste geführt wird,
wird in der Datenkbank mitgespeichert.
Gegeben sei eine 1:n - Assoziation.
Die 1-Seite hat die betreffende Collection mit Entitäten der n-Seite.
Diese Collection kann als List definiert sein in der Klasse der Entität.
Möchte man die Reihenfolge der Liste aber immer deterministisch haben, dann muss
die Reihenfolge mitgespeichert werden. Hierzu gibt es eine neue Annotation in JPA 2:
@OrderColumn

@Entity
public class A implements Serializable {
   ...
   @OneToMany
   @OrderColumn
   private List<B> bs = new ArrayList<B>();
   ...
}    

@Entity
public class B implements Serializable {
 ...
 @Id
 @Generated
  private Long id;
  private String orderNumber;
 ...
}

In diesem Fall wird in der Entität B ein von der Entität nicht sichtbares Feld angelegt mit dem Namen
BS_ORDER, welches dazu dient, die Reihenfolge der assozierten Entitäten von B zu A festzuhalten.
Somit ergibt sich immer wieder die gleiche Reihenfolge Elemente in der Collection, wenn die Entitäten von A geladen werden z.B. im Modus FetchType.EAGER.

Wann anwenden?
Wenn eine Sortiervorschrift @OrderBy die Zugriffszeit unnötig verschlechtert oder die Sortierung nach fachlichen Attributen / Spalten immer noch eine undefinierte Sortierung hervorbringt.

Das Speichern von Elementen per Key bei einer Assoziation, die als Map realisiert wurde,
war auch mit der vorherigen JPA Version möglich:
Im obrigen Beispiel ist bs nicht als List angegen worden, sondern als Map.
Dann kann mit der Annotation @MapKey der Schlüssel festgelegt werden, mit der man auf
die Collection / Assoziation zugreifen möchte.
Im Default bezeichnet @MapKey immer den primary key der Entität.
Möchte man eine andere Spalte als Schlüssel für die Map definieren, kann man dies mit
@MapKey(name="columnName") festlegen.
So ergibt sich nach obigen Beispiel:
   @OneToMany
   @MapKey(name="orderNumber")
   private Map<String, B> bs = new HashMap<String,B>();

Wozu der keybasierte Zugriff auf Assoziatioen?
Der macht Sinn, wenn man weiß, dass bei dieser Annotation der Zugriff
aus der Fachlogik meistens mit der orderNumber erfolgt und der pk ein technischer Schlüssel ist,
der in anderen Use Cases wie Beispiel Archivierung eher zum Zuge kommt.
Dann lässt sich schön ausdrücken:
String aOrderNumber;
....
B myBEntity = a.getBs().get(aOrderNumber);


Keine Kommentare:

Kommentar veröffentlichen