Frage zu @PreUpdate und @PrePersist

Dieses Thema Frage zu @PreUpdate und @PrePersist im Forum "Data Tier" wurde erstellt von SilencerandLois, 17. Jan. 2014.

Thema: Frage zu @PreUpdate und @PrePersist Hallo zusammen, durch Recherche zum Thema Auditierung bin ich auf die Annotation @PreUpdate und @PrePersist...

  1. Hallo zusammen,
    durch Recherche zum Thema Auditierung bin ich auf die Annotation @PreUpdate und @PrePersist gestoßen (wir verwenden Java EE 5).
    Was ich dadurch schonmal erreichen kann ist, dass ich automatisiert ein Erstellungsdatum / Änderungsdatum in der Entität setzen kann. Soweit so gut.
    Ich möchte aber nun noch zusätzlich den Benutzer in der Entität anpassen, sollte ein neuer Datensatz angelegt oder ein Update auf diesem durchgeführt werden.

    Leider habe ich auf Ebene der Entität keine Möglichkeit, den Sessionkontext abzurufen, da die Entitäten bei unserer gewählten Architektur wie folgt aussehen (wir verwenden als O/R-Mapper Eclipselink):

    Code (Java):

    @Entity
    public class XY implements {
    }
     

    Hat jemand von euch eine Idee, wie ich nun automatisiert bei einer Neuanalge / Änderung einer Entität neben den Zeitstempeln auch noch den Benutzer setzen kann?

    Besten Dank für eure Hilfe!
    Martin


    Den Sessionkontext hätte ich bei einer EJB-Entität wie folgt geholt:
    Code (Java):

    context.getCallerPrincipal().getName()
     
     
  2. Vielleicht hilft dir das Java-Tutorial weiter. Hier klicken --> (Klick)
  3. Gar nicht..dafür sind PrePersist/.. nicht gedacht.

    Die Spec sagt
    Hibernate verbietet es sogar
    Dafür musst du wahrscheinlich Provider-spezifische Funktionen verwenden..bei Hibernate wären das Listener (Hiberante < 4). Später wurde dann ein entsprechendes SPI eingeführt..siehe Hibernate-Dok
     
  4. Dachte ich mir schon fast :-(
    Gibt es eine ähnliche Funktionalität bei eclipselink?

    Wo würdet ihr ansonsten das Attribut setzen? In der Business-Logik?

    Danke!
     
  5. -- Frage wurde wieder entfernt --
     
    Zuletzt bearbeitet: 20. Jan. 2014
  6. Also wenn ich so etwas implementieren müsste, würde ich es tatsächlich in der Business-Logik machen und nicht im Datenmodell.

    Wenn du aber ganz dreist sein willst, könntest du das vielleicht mit einer Factory lösen, die dir den passenden Session-Context liefert. Die Factory könntest du dann in deiner PrePersist-Methode verwenden. Was ich dir aber nicht empfehle.

    Denn: Wenn dein Datenmodell entscheidet, welcher Benutzer nun genau zur Entity gehört, so kann es unter Umständen sein, dass du keine Chance haben wirst, dich drüber im Falle des Falles hinweg zu setzen. Zudem der nächste, der auf den Code schaut, sich beim Debuggen einen Wolf sucht.
     
    Zuletzt bearbeitet: 22. Jan. 2014
  7. Danke Spitfire für deinen Kommentar.

    Das Factory-Pattern kenn ich schon. Aber wie würdest du das Umsetzen? Damit die Factory die Session kennt, müsste diese doch ein EJB sein, in welcher die Session über
    Code (Java):

    public void setSessionContext(final SessionContext sessionContext) {
    }
     
    automatisch durch JEE gesetzt wird. Wie kann ich aber dann von der Entität des Datenmodells auf die Factory-Klasse zugreifen? Oder verstehe ich deinen Lösungsansatz falsch?

    Sitz gerade auf dem Schlauf :oops:
    Wennsd kurz ein paar erklärende Codeschnippsel posten könntest, wäre ich dir sehr Dankbar!

    Viele Grüße,
    Martin

    P.S.: Dein Einwand mit der engen Kopplung beim Setzen des Benutzers im Datenmodell ist berechtigt. Stellt aber bei unseren fachlichen Bedürfnissen kein Problem dar. Diese könnten sich zwar natürlcih ändern, was ich in diesem Kontext jedoch stark bezweifle.
     
  8. Öhm ich glaub kaum dass das funktionieren wird. Vermutlich kriegst du vom Persistenceprovider auf die Finger weil an der Stelle keine Interaktion mehr mit der Session machen darf .
    Was er meint ist den EntityManager in ein Singleton ( oder besser ThreadLocal) zu packen... dann kommst aus dem PrePersist dran.
     
  9. Ich weiß, es ist nicht die schönste Art von der Datenschicht auf die Session zuzugreifen.
    Muss man abwägen anhand der Architektur bzw. Modularisierung.

    Mit Spring Securtiy:

    private String getUsername()
    {
    try
    {
    final User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    return user.getUsername();
    }
    catch (final Exception e)
    {
    return "system";
    }
    }

    Man kann das aber mit Sicherheit noch entkoppeln. Session über Interface an Bean koppeln, etc ....
     
  10. Ich wollte das Problem nun mit einer ThreadLocal-Variable lösen.
    Leider klappt es nicht so ganz.

    Was habe ich gemacht:
    1) In einem zentralen EJB-Container komme an meine Session. Hier lege ich den Benutzer nun in einer ThreadLocal-Variable ab. Durch Debuggen habe ich evaluiert, dass der Wert dort korrekt abgelegt wird. Die Methode wird auch nur ein einzigstes Mal beim Einloggen des Benutzers ausgeführt.
    Code (Java):

    class BusinessObject{
        public static final ThreadLocal<String> getAdmbName = new ThreadLocal();

        ....

        getAdmbName.set(context.getCallerPrincipal().getName());
     
    2) In meiner Entität greife ich nun in der mit @PreUpdate-Annotierten-Methode auf diese ThreadLocal-Variable zu. Ich befinde mich auch noch im selben Thread. Die Variable ist jedoch nicht gefüllt.
    Code (Java):

    @Entity
    class Entität {
       ...

       String getAdmbName = BusinessObject.getAdmbName.get();

       ...
    }
     
    Sollte es nicht so sein: wenn ich in einem einzelnen Thread unterwegs bin, dann kann ich bedenkenlos auf diese Variable zugreifen?


    Danke!
    Martin
     
    Zuletzt bearbeitet: 28. Jan. 2014
  11. versuchs mal mit InheritableThreadLocal...
     
  12. Hat leider auch nichts gebracht
     
  13. Problem gelöst.
    Ich weiß zwar nicht WARUM ich das Problem hatte, jedenfalls berechne ich die Thread-Local-Variable in einer anderen Klasse. Hier funktioniert nun auch der Zugriff.

    Ich verstehs zwar noch nicht ganz, da es eigentlich auch vorher der selbe Thread hätte sein sollen, aber was solls. Hauptsache, es läuft nun. :toll:

    Danke für die Hilfe!
    Martin
     
  14. Schau dir jetzt hier den Kurs an und lernen Java zu programmieren: --> Hier klicken, um mehr zu erfahren (Klick)