Jul 032007
 

Mehrfach verwendet man im Datenmodell / Domänenmodell ein Attribut, welches “dateCreated” oder ähnlich heisst. Für eine Entität soll also hinterlegt sein, wann diese erstellt worden ist. Hat man erst einmal ein solches Attribut an einer Entität, so muss das Erstellungsdatum auch beim erstmaligen Persistieren der Entität gesetzt werden. Wie kann man derartiges unter Verwendung der Java Persistence API effizient umsetzen?

Ein erster Gedanke könnte sein – klar, das machen die DAOs. Das DAO wird aufgerufen um eine Entität in der aktuellen Transaktion in der Datenbank zu erstellen. Dann kann das DAO prüfen, ob das Attribut “dateCreated” gesetzt ist und ggf. das aktuelle Datum als Wert setzen. Wenn jedoch mit Persistence-Kaskadierung (JPA CascadeType.PERSIST) gearbeitet wird, so kann sich die Umsetzung dieses Mechanismus im DAO schwierig bis nicht mehr sinnvoll möglich gestalten.

Beispiel: Im System gibt es die Entitätstypen Person und Address. Zwischen Person und Address besteht eine 1-N-Relation. Für Address gibt es das Attribut “dateCreated”. Es wird ein neues Person-Objekt mitsamt eines neuen, dem Person-Objekt zugeordneten Address-Objekt erzeugt. Die Relation zwischen Person und Address besitzt “CascadeType.PERSIST” bzw. CascadeType.ALL”. Das Person-Objekt wird mitsamt des Address-Objekt persistiert, indem am PersonDAO die Methode “persist” mit dem Person-Objekt als Argument aufgerufen wird. Das AddressDAO ist nicht beteiligt und kann daher auch nicht den Wert des Attributs “dateCreated” setzen.

Nun könnte man wieder den AspectJ-Laser auspacken um das Problem generell und effizient zu lösen, doch es geht auch weniger komplex: Die JPA-Annotation “PrePersistence”, welche eine Callback-Methode in der Entitätsklasse definiert. So sieht das ganze dann aus:

 1 import java.util.Date;
 2 import javax.persistence.AttributeOverride;
 3 import javax.persistence.Column;
 4 import javax.persistence.Entity;
 5 import javax.persistence.PrePersist;
 6 import javax.persistence.Table;
 7 import javax.persistence.Transient;
 8 
 9 @Entity
10 @Table(name = "ADDRESS")
11 @AttributeOverride(name = "id", column = @Column(name = "ID"))
12 public class Address extends AbstractDomainEntity {
13 
14   private static final long serialVersionUID = 1L;
15 
16   private java.util.Date dateCreated;
17 
18   public Address() {
19   }
20 
21   @Column(name = "DATE_CREATED", nullable = false)
22   public java.util.Date getDateCreated() {
23     return dateCreated;
24   }
25 
26   public void setDateCreated(java.util.Date pDateCreated) {
27     dateCreated = pDateCreated;
28   }
29 
30   @PrePersist
31   @Transient
32   public void setDateCreatedIfRequired() {
33     if (this.dateCreated == null) {
34       dateCreated = new Date();
35     }
36   }
37 
38 }
39 

Die Methode “setDateCreatedIfRequired” wird durch die Angabe “@PrePersist” von der JPA-Implementierung am Entitätsobjekt aufgerufen, bevor die Entität in der Datenbank persistiert wird. Wenn noch nicht vorhanden, wird das Erstellungsdatum der Entität gesetzt (“dateCreated”).

Anmerkung: Die Basisklasse AbstractDomainEntity stellt das Attribut “id” bereit. Natürlich hat eine Entität “Address” etwas mehr Attribute als “id” und “dateCreated”.

Ein Datenbanktrigger könnte für dieses Problem natürlich auch herhalten, allerdings muss nach dem Persistieren einer Entität, der entsprechende Wert aus der Datenbank ermittelt werden, was natürlich auch seine Schattenseiten hat. Ich finde, die obige Lösung ist einfach, klar und ist ausreichend flexibel. Was meinst Du?

  2 Responses to “JPA PrePersist für Erstellungsdatum von Datensätzen / Entitäten nutzen”

  1. Wofür ich noch keine Lösung habe, ist die Frage, wie man innerhalb der @PrePersist-Methode auf bestehende Daten zugreift. Es darf anscheinend in dieser kein Zugriff auf den EntityManager stattfinden.

  2. Ebenfalls hilfreich ist auch @PreUpdate, was eine schnelle, elegante Annotation ist für Felder wie z.B. “lastModified”.

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>