Historisierung - Alter Wert, Neuer Wert... wie speichern?

internet

Top Contributor
Hallo,

ich möchte ich meiner Applikation eine Historisierung machen.

1. Objekt wird geändert
-> Wert in der Datenbank geändert

2. Historisierung speichern
-> Es wird genau dokumentiert, was geändert wurde. (Alter Wert vs. Neuer Wert)

Bspw. wie hier:
1646805852830.png

Ich speichere in der DB ja nicht mehrmals nun das Objekt, sondern der Wert wird ja überschrieben.

Wie macht man das in der Praxis?
- Hat man bpsw. eine History - Datenbank Tabelle:
-> Man erstellt vor dem Speichern ein JSON Objekt vom alten Wert des Objekts
-> Man erstellt nach dem Speichern ein JSON Objekt vom neuen Wert des Objekts

Oder wie macht man das?
 

KonradN

Super-Moderator
Mitarbeiter
Wir haben sowas in der Regel in der Datenbank gemacht mit Triggern, und der Trigger ist verantwortlich für die History Einträge.
 

internet

Top Contributor
danke für die Info....
Wenn ich es aber richtig lese, muss ich dann für jede einzelne Entität eine weitere Tabelle anlegen?

Nach diesem Schema ist nun für jede zu auditierende Tabelle eine Audittabelle anzulegen.
 

LimDul

Top Contributor
danke für die Info....
Wenn ich es aber richtig lese, muss ich dann für jede einzelne Entität eine weitere Tabelle anlegen?

Ja klar, da wirst du nicht drum rumkommen. Irgendwo müssen ja die historisierten Daten gespeichert werden
 

LimDul

Top Contributor
Dann hast aber unstrukturierte Daten, die sich sehr sehr schwer auswerten lassen. Weil du sie als Blob, String (Egal ob Json oder XML ablegen muss). Was wiederum heißt, du musst für jede Entity eine saubere String-Darstellung bauen. Wo ist das Problem bei 200 Tabellen? Das ist täglich Brot einer Datenbank Tabellen zu haben.
 

Marinek

Bekanntes Mitglied
Alles andere würde nicht der 3. Normalform genügen.
Du müsstest alle Felder so oft duplizieren, wie du das Audit speichern willst.
Ob du 200 oder 400 Tabellen hast, dann ist das Dann auch nicht tragisch.
Du kannst ja schauen, ob es bestimmte Relationen gibt, die ein Audit benörigen und welche nicht.
 

KonradN

Super-Moderator
Mitarbeiter
Die Frage ist wirklich, was die genauen Anforderungen sind. Das hört sich jetzt mehr nach einem Logging an. Und entsprechend so kann man das dann auch bauen.

Aber das nur als Nennung einer weiteren Idee.
 

Neumi5694

Top Contributor
Du kannst grundsätzlich jeden Dateneintrag nicht als einzelnen Wert, sondern als History-Tabelle hinterlegen. Der aktuelle Wert ist dann immer der letzte.
Wenn du die Daten immer als Ganzes abspeicherst und nicht über einzelne Felder, kannst du auch einfach ein Image der gesamten Struktur sichern. Braucht zwar mehr Speicherplatz, ist aber die einfachste Lösung. Wenn du wissen willst, was geändert wurde, vergleichst du dann die gesamte Struktur.
 

internet

Top Contributor
Du kannst grundsätzlich jeden Dateneintrag nicht als einzelnen Wert, sondern als History-Tabelle hinterlegen. Der aktuelle Wert ist dann immer der letzte.
Wenn du die Daten immer als Ganzes abspeicherst und nicht über einzelne Felder, kannst du auch einfach ein Image der gesamten Struktur sichern. Braucht zwar mehr Speicherplatz, ist aber die einfachste Lösung. Wenn du wissen willst, was geändert wurde, vergleichst du dann die gesamte Struktur.
Naja, also eigentlich will ich nur dem User die Möglichkeit schaffen, dass er sieht, was sich geändert hat (siehe Scrennshot eingangs...). Also eigentlichen dann "Logging"...
Ich benötige nicht zwingend die Möglichkeit bpsw. das Objekt zurückzuholen, das vor 30 Tage gespeichert wurde bspw.

Daher war mein Ansatz eine Tabelle zu haben:
Tabelle "History", mit den Felder:
- String oldValue
- String newValue

-> In oldValue speichere ich dann das JSON Objekt zum damaligen Zeitpunkt
-> In newValue speichere ich dann das JSON Objekt zum jetzigen Zeitpunkt

-----
Wenn man sich dann in der GUI die Unterschiede ansehen möchte, dann gibt es eben noch eine Methode, die beide Objekte vergleicht und dann nur die Properties ausgibt, die sich unterscheiden...

Sowas hier:
1646818194695.png



1646818216793.png
 

LimDul

Top Contributor
Und wie ist das mit Objektbeziehungen? Also eine Klasse A, die eine Liste von Elementen der Klasse B hat.

Die Standard-JSON Darstellung wäre ja, dass die Elemente B als Sub-Elemente drin wären. Sprich du hättest das gesamte Objektgeflecht drin. Wenn sich nun einem Attribut in A was ändert, sollen dann in der Json-Darstellung alle Elemente von B drin sein?

Wie sieht es mit Hinzufügen/Löschen von Elementen aus? Wie soll das dargestellt werden?

Ich sehe da zwei grundsätzliche Ansätze:

a) Die Historisierung über Hibernate
Pro:
* Einfach umzusetzen
* Vollständig
Contra:
* Es wird alles historisiert

b) Die Historisierung selber bauen
Pro:
* Man kann genau das speichern, was sich geändert
Contra:
* Aufwendiger einzubauen


Ich würde bei b) anstelle auf Json zu gehen es auch lieber generischer machen, also eine Tabelle der Form

Spalten zur Objekt-Identifikation
Spalte Attribut-Name
Spalte Alter Wert
Spalte Neuer Wert

Dann musst du weniger speichern.
 

Neumi5694

Top Contributor
Wenn du eh mit Json arbeitest, kannst du ja anstatt 2 Feldern ein Objekt mit 2 Werten verwenden (aktueller Wert, letzter voriger Wert).
Ich hab das für mehrsprachige Bezeichnungen usw. gemacht. Anstatt in jedem Datenobjekt x Felder pro Sprache anzulegen, hab ich eine Klasse für mehrsprachige Texte angelegt, das dann an allen Stellen zum Einsatz kommt, wo mehrere Sprachen unterstützt werden sollen.

Die Daten auf eine Art rauszuziehen, wie du das im Screenshot machst, wird so aber ziemlich kompliziert.

Was du hier zeigst, ist eben genau ein Log.
D.h. dir reicht EINE Tabelle, in der du jede Aktion protokollieren musst. Wer, Wann, Was, Von, Nach.

Dafür musst du dann halt jedesmal, wenn irgendwo ein Wert geändert wird, einen Log-Eintrag schreiben.
 

internet

Top Contributor
prinzipiell baue ich das lieber selbst, damit ich mehr Flexibilität habe...
Die Frage ist gerade nur wie :)

Aktuell habe ich eine Tabelle, die zwar Aktivitäten (Tabelle History) loggt.
Aber nur was genau gemacht wurde (CRUD). Also ob etwas "erstellt", "geändert", "gelöscht" wurde...

Prinzipiell geht es nur um das Logging bei "Änderungen":
Nun möchte ich aber den nächsten Schritt gehen um zu sehen, WAS genau geändert wurde...
Prinzipiell soll es pro Änderung auch nur einen DB - Eintrag geben.
Also ich will nicht, dass ich bpsw. innerhalb einer Änderung - Operation insgesamt 5 Felder ändere und dann auch 5 DB - Einträge habe.... Daher meine Idee die Änderungen in einem String (XML / JSON) zu speichern, hier sehe ich aber mehr Probleme auf mich zu kommen (Datentypen etc.)

Ggf. wäre auch das möglich, sodass ich noch eine zweite Tabelle (HistoryValue) erstelle...

Tabelle History
- String type (mögliche Werte CREATE, MODIFY, DELETE)

Tabelle HistoryValue
- String entityType
- Long objectId
- String fieldName
- String valueOld
- String valueNew
- HistoryFK (Referenz auf History - Tabelle) -> Damit könnte man dann eben pro Operation alle Felder bekommen, die sich geändert haben...

Da meine Applikation auch Mehrsprachigkeit unterstützt, habe ich dann auch das Problem um herauszufinden, wie das entsprechende Feld in der unterschiedliche Sprache heißt...

Beispiel:
Ich ändere den Vornamen von: Markus zu Dieter...
Nun soll in der GUI eines deutschen User das Feld eben "Vorname" sein, bei einem englischsprachigen User "Surname"...

Hierfür wäre dann der Ansatz, den Feldname in der Tabelle zu speichern (String fieldName)...
Anhand einer Custom Annotation über jedem Feld bei der Entity, könnte ich das ja dann rausfinden.
Und dann eben dynamisch bei der entsprechenden Klasse (EntityType) das Feld heranzieht und dann die Annotation herausfindet, die mir den Feldnamen in der entsprechenden Sprache gibt.

Also sprich von der Sprache - Datei, wie man es bei der Bean Validation etc. macht:
Java:
@NotNull(message="{myBean.name.null.message}")

Beim Erstellen und Löschen reicht eigentlich nur:
a) Datensatz wurde erstellt
b) Datensatz wurde gelöscht
 

internet

Top Contributor
das meine ich doch...?

1. In der Tabelle "HistoryValue" speichere ich ja nur den Feldnamen.
2. Anhand Custom Annotations pro Feld, speichere ich Infos zu diesem Feld (Name etc.)
- Eine Information ist bpsw. "languageFeld="{myEntity.fieldName}"
- {myEntity.fieldName} führt zur Property Datei, in der dann der entsprechende Sprachtext steht
 

Neumi5694

Top Contributor
Die mehrsprachigen Label eines GUI in der DB abzulegen scheint mir doch recht umständlich. Die Label-Texte liegen normalerweise in Property-Dateien in der jeweiligen Sprache. Das nennt sich: Internationalizing - https://docs.oracle.com/javase/tutorial/i18n/intro/steps.html
Ich hab nicht von GUI-Labels gesprochen, sondern von Daten. Die UI kriegt die Texte über Properties, da sind wir einer Meinung
.
Es handelt sich in meinem Fall aber um durch den Benutzer erstellte Datensätze, die mehrsprachig benannt werden können müssen, z.B. ein Artikel oder Material, dessen Name und Kurzbeschreibung in mehreren Sprachen verfügbar sein soll (die anderen Eigenschaften sind natürlich sprachunabhängig). Dafür wäre eine properties-Datei ganz und gar nicht geeignet.
 
Zuletzt bearbeitet:

internet

Top Contributor
Sorry für die späte Antwort.
Nein, die Text für Artikel etc. speichere ich in einer weiteren Tabellen, die dann jeweils die Sprachtexte enthält (ähnlich, wie das zB in SAP geschieht).

Bzgl. dem Vergleich bei einem Objekt, was sich geändert hat.
Gibt es hierzu ein Framework, in dem ich von einer Klasse zwei Objekte in einer Methode gebe und ich dann nur die Attribute zurückbekomme, bei denen sich der Wert unterscheidet?
Klar, könnte ich das nun auch selbst bauen und mit zig "equals" - Abfragen das prüfen, aber vllt. kann man das auch einfacher lösen?

Ansonsten wäre mein Ansatz nun eher folgender:

Tabelle History
- String type (mögliche Werte CREATE, MODIFY, DELETE)
- String für XML / JSON

im Json / XML String, speichere ich dann diese Infos:

HistoryValue
- String entityType (Klassenname bzw. JPA Tabelle)
- Long objectId (ID in DB auf das Objekt)
- String fieldName (Feldname)
- String dataType (Datentyp)
- String valueOld (Wert alt)
- String valueNew (Wert neu)
 

mrBrown

Super-Moderator
Mitarbeiter
Warum willst du in einer relationalen Datenbank JSON-Objekte (keine Arrays!) mit fester(!) Struktur speichern?

Und abgesehen davon: auf Dauer machst du es dir deutlich einfacher, pro Tabelle eine zusätzliche (gleich aufgebaute) Tabelle für Änderungen zu nutzen, anstatt das für alle Spalten aller Tabellen in einem Feld abzubilden.
 

internet

Top Contributor
Warum willst du in einer relationalen Datenbank JSON-Objekte (keine Arrays!) mit fester(!) Struktur speichern?
Andere Option wäre eben eine zweite Tabelle (siehe oben), die dann für jedes Feld die Änderung (alter Wert / neuer Wert) speichert. Also:

HistoryValue
- String entityType (Klassenname bzw. JPA Tabelle)
- Long objectId (ID in DB auf das Objekt)
- String fieldName (Feldname)
- String dataType (Datentyp)
- String valueOld (Wert alt)
- String valueNew (Wert neu)

Sehe aber nicht unbedingt einen Grund, was dagegen spricht es in JSON zu speichern und dann diesen JSON als String nur in der "History" - Tabelle zu speichern. Ich brauche ja ja nur die Info:

1. Entity wurde geändert.
2. Welche Informationen (Felder) wurden geändert.

Und abgesehen davon: auf Dauer machst du es dir deutlich einfacher, pro Tabelle eine zusätzliche (gleich aufgebaute) Tabelle für Änderungen zu nutzen, anstatt das für alle Spalten aller Tabellen in einem Feld abzubilden.
Das ist für mich keine Lösung bei über 300 Tabellen. Das ist der Aufwand einfach viel zu groß, für das was am Ende der Nutzen ist.
 

KonradN

Super-Moderator
Mitarbeiter
Das ist für mich keine Lösung bei über 300 Tabellen. Das ist der Aufwand einfach viel zu groß, für das was am Ende der Nutzen ist.
Wenn Du es mit Envers machst, dann werden die Tabellen doch auch automatisch angelegt - so habe ich das zumindest verstanden. Daher ist der Aufwand deutlich geringer.

Und der Aufwand verringert sich noch beim Zugriff, denn du kannst übder die angebotene API in Java problemlos auf die Daten zugreifen.

Wenn Du alles drekt in Java ("Code first") machst und die Dtaenbank generiert wird und so, dann ist die Idee aus #4 mit die beste Lösung mit minimalem Aufwand.

Wenn Du die Datenbank selbst verwaltest (Das hatte ich in Projekten in der Vergangenheit), dann wird das alles manuell gemacht, aber da täuscht die Arbeit. Die notwendigen Tabellen (Und bei uns auch Trigger, da das Auditing von der Datenbank gemacht wurde) konnten aus den vorhandenen Tabellen generiert werden. Das ist ein klares Schema F das anzuwenden ist. (Die Generierung bietet auch den Vorteil, dass Du die Methodik einmal getestest hast und Du dann eben nicht 300 Implementationen hast, die Du irgendwie testen musst um ggf. Fehler zu identifizieren wie ein Feld vergessen oder so ...)
 

internet

Top Contributor
Was soll den genau der Nutzen sein? Sorry, falls diese Frage bereits oben irgendwo beantwortet wurde.

Im einfachsten Fall, kannst du ja einfach eine Art von Log schreiben: "Benutzer xy hat das Feld z von a nach b geändert."

Ansonsten werfe ich jetzt einfach mal den Begriff Event Sourcing in den Raum. Wobei das wohl etwas zu hoch gegriffen ist.
Nachvollziehbarkeit...

In diesem Screenshot sieht man es eig. ganz deutlich.
Es soll nachvollziehbar sein:
- Welcher User
- Welche Änderung wann gemacht hat

1648712812901.png

"Farbe" ist diesem Fall das Feld einer Klasse.
Nebendran dann eben "Alter Wert", "Neuer Wert"
 

mrBrown

Super-Moderator
Mitarbeiter
Andere Option wäre eben eine zweite Tabelle (siehe oben), die dann für jedes Feld die Änderung (alter Wert / neuer Wert) speichert. Also:

HistoryValue
- String entityType (Klassenname bzw. JPA Tabelle)
- Long objectId (ID in DB auf das Objekt)
- String fieldName (Feldname)
- String dataType (Datentyp)
- String valueOld (Wert alt)
- String valueNew (Wert neu)

Sehe aber nicht unbedingt einen Grund, was dagegen spricht es in JSON zu speichern und dann diesen JSON als String nur in der "History" - Tabelle zu speichern. Ich brauche ja ja nur die Info:
Es gibt da ein ganz interessantes Konzept in relationalen Datenbanken: Spalten.
 

temi

Top Contributor
Nachvollziehbarkeit
Schon klar. Nachvollziehen kannst du es auch, wenn du in ein Log schreibst, wer, was, wann gemacht hat. Nur das Finden dieser Information ist dann etwas schwieriger.

Aber genau das ist der Punkt. Wie oft benötigst du genau diese Information?

Nur falls irgendwann, vielleicht eine Unregelmäßigkeit aufgetreten ist und man analysieren möchte, was passiert ist oder wer es gewesen ist?
Oder immer, wenn z. B. auf ein Datenfeld geklickt wird, um sofort die vollständige Änderungshistorie anzuzeigen?

Das sind unterschiedliche Qualitäten, die einen unterschiedlichen Aufwand benötigen. Letztlich sollte man nicht mehr Aufwand hineinstecken, als den, der notwendig ist, um das gewünschte Ziel zu erreichen.
 

Neumi5694

Top Contributor
Ich bin immer noch der Meinung, dass ein stinknormales Log hier reichen würde, es ist schließlich nicht Absicht, dass vorherige Zustände wiederhergestellt werden. Für die gewünschte Auswertung (siehe Post #12) muss nur protokolliert werden, wer wann was wovon wonach geändert hat.
Meldungen filtern dürfte nun wirklich kein Problem darstellen.
 

internet

Top Contributor
Es gibt da ein ganz interessantes Konzept in relationalen Datenbanken: Spalten.
Verstehe ich nicht, wie bei dir dann das Datenmodell aussehen würde. Wenn man später ggf. wirklich auswerten möchte, welches Feld wie oft geändert wurde, gebe ich dir Recht, dass eine SQL Tabelle die bessere Wahl ist. Meine gedachtes Datenmodell habe ich oben bereits gepostet.

Schon klar. Nachvollziehen kannst du es auch, wenn du in ein Log schreibst, wer, was, wann gemacht hat. Nur das Finden dieser Information ist dann etwas schwieriger.

Aber genau das ist der Punkt. Wie oft benötigst du genau diese Information?

Nur falls irgendwann, vielleicht eine Unregelmäßigkeit aufgetreten ist und man analysieren möchte, was passiert ist oder wer es gewesen ist?
Oder immer, wenn z. B. auf ein Datenfeld geklickt wird, um sofort die vollständige Änderungshistorie anzuzeigen?

Das sind unterschiedliche Qualitäten, die einen unterschiedlichen Aufwand benötigen. Letztlich sollte man nicht mehr Aufwand hineinstecken, als den, der notwendig ist, um das gewünschte Ziel zu erreichen.
Ich möchte nicht nachvollziehen, wann ein User einen Button gedrückt hat.
Ich möchte nachvollziehen, wenn ein User eine Entität gespeichert, geändert und ggf. gelöscht hat.
Es soll also wie ein Protokoll sein für die Nachvollziehbarkeit.

Ich bin immer noch der Meinung, dass ein stinknormales Log hier reichen würde, es ist schließlich nicht Absicht, dass vorherige Zustände wiederhergestellt werden. Für die gewünschte Auswertung (siehe Post #12) muss nur protokolliert werden, wer wann was wovon wonach geändert hat.
Meldungen filtern dürfte nun wirklich kein Problem darstellen.
Wie sieht bei dir ein "stinknormales Log" aus? In der Textdatei?
-> Falls in SQL, wie sieht hier das Datenmodell aus?

Mit dem von mir geposteten Datenmodell oben, könnte man bspw. mit Reflection die entsprechenden Felder wieder füllen und somit ebenfalls den Zustand wieder herholen.

Man hat im Zugriff:
- Klassenname
- Feldname
- Alter Wert / Neuer Wert

Anschließend schreibt man eben eine Methode, die mir die Klasse holt, das Feld und schreibt dann den alten Wert wieder mittels der SET - Methode rein. Habe es nicht getestet, aber sollte so gehen.

Das Prozedere sähe dann so aus:
1) Erstelle einen neuen Eintrag in Tabelle "History"
- Datum
- UserFK
- CRUD Type (zB als Enum)

2) Rufe Methode auf und vergleiche die zwei Objekte.
Speichere in der Tabelle "HistoryValue" nur die Einträge, bei denen die zwei Objekte sich unterscheiden.

Die eigentliche Frage ist nun allerdings noch, wie ich zwischen zwei Objekte von einer Klasse, nur die Unterschiede bzw. die Felder bekomme, die einen Unterschied im Wert aufweisen (ohne dafür jedes einzelne Feld via "equals" zu prüfen.

Wäre das nicht ggf. auch durch Reflection notwendig?
 

mrBrown

Super-Moderator
Mitarbeiter
Dein geplantes Schema ist:
type
entityTypeobjectIdfieldNamedataTypevalueOldvalueNew
Also eine Spalte, in der 6 andere Spalten abgebildet sind, verpackt in JSON oder XML.

einfacher wäre einfach ein:
typeentityTypeobjectIdfieldNamedataTypevalueOldvalueNew
 

temi

Top Contributor
Ich möchte nicht nachvollziehen, wann ein User einen Button gedrückt hat.
Ich möchte nachvollziehen, wenn ein User eine Entität gespeichert, geändert und ggf. gelöscht hat.
Es soll also wie ein Protokoll sein für die Nachvollziehbarkeit.
Das hatte ich schon verstanden. Aber letztlich geht es darum, wie oft du diese Funktionalität in welcher Tiefe benötigen wirst.
Wenn man später ggf. wirklich auswerten möchte, welches Feld wie oft geändert wurde
Genau dieses. Die Möglichkeit dafür kann man sicher schaffen, aber wird man das jemals benötigen?

Du solltest nur soviel Aufwand in die Sache stecken, wie notwendig ist, um dein Ziel zu erreichen. Dazu musst du dein Ziel kennen und es sollte nicht nur "Nachvollziehbarkeit" lauten. Nachvollziehen kannst du Änderungen auch, wenn du tatsächlich einfach Logging in ein Textfile machst. Dann ist der Aufwand, etwas "nachzuvollziehen" halt etwas höher, aber wenn es eh nur selten oder evtl. gar nicht benötigt wird, reicht das aus.

Auf der anderen Seite, ist es z. B. für ein Dokumenten-Management-System schon sinnvoll mehr Aufwand hinein zu stecken, weil hier auch User diese Informationen vielleicht öfter benötigen.

Ich kenne dein System nicht, weiß also nicht, wie relevant diese Informationen im täglichen Gebrauch sind. Aber nur "weil das vielleicht mal jemand machen möchte" würde ich keinen gesteigerten Aufwand betreiben.
 

internet

Top Contributor
Dein geplantes Schema ist:
type
entityTypeobjectIdfieldNamedataTypevalueOldvalueNew
Also eine Spalte, in der 6 andere Spalten abgebildet sind, verpackt in JSON oder XML.

einfacher wäre einfach ein:
typeentityTypeobjectIdfieldNamedataTypevalueOldvalueNew
danke... glaube dann haben wir uns etwas falsch verstanden.
Wenn ich eine weitere Tabelle anlege (HistoryValue), hätte die auch so ausgesehen, nur dass ich
type, entityType, objectId herauslassen würde, da ich diese in der "Kopf Tabelle (=History)" bereits habe.
Zusätzlich käme dann eben ein FK in die Tabelle mit rein ("historyFk").

Dann hat eben eine Änderung 1....n geänderte Felder

Das hatte ich schon verstanden. Aber letztlich geht es darum, wie oft du diese Funktionalität in welcher Tiefe benötigen wirst.

Genau dieses. Die Möglichkeit dafür kann man sicher schaffen, aber wird man das jemals benötigen?

Du solltest nur soviel Aufwand in die Sache stecken, wie notwendig ist, um dein Ziel zu erreichen. Dazu musst du dein Ziel kennen und es sollte nicht nur "Nachvollziehbarkeit" lauten. Nachvollziehen kannst du Änderungen auch, wenn du tatsächlich einfach Logging in ein Textfile machst. Dann ist der Aufwand, etwas "nachzuvollziehen" halt etwas höher, aber wenn es eh nur selten oder evtl. gar nicht benötigt wird, reicht das aus.

Auf der anderen Seite, ist es z. B. für ein Dokumenten-Management-System schon sinnvoll mehr Aufwand hinein zu stecken, weil hier auch User diese Informationen vielleicht öfter benötigen.

Ich kenne dein System nicht, weiß also nicht, wie relevant diese Informationen im täglichen Gebrauch sind. Aber nur "weil das vielleicht mal jemand machen möchte" würde ich keinen gesteigerten Aufwand betreiben.
Ich denke anhand dem geposteten Screenshot sollte es klar sein, was ich gerne habe.

Offene Frage ist eben noch, wie ich die Unterschiede der zwei Objekte identifiziere?
 

LimDul

Top Contributor
Offene Frage ist eben noch, wie ich die Unterschiede der zwei Objekte identifiziere?
Das ist nicht trivial. Das musst du im Prinzip für jedes Attribut prüfen und ggf. anpassen.

Wir haben das bei uns im Modelling-Framework über einen Visitor-Pattern gelöst. Der bekommt zwei Objekte A und B reingegeben und besucht alle Attribute. Zusätzlich gibt es eine Konfiguration, die entscheidet, ob zwei Objekte gleich sind bzw. ob zwei Attribute gleich sind. Standardmäßig wird das über == und equals geprüft, aber das funktioniert nicht für alles. Insbesondere bei Listen hat man ein Problem, wenn die Reihenfolge unterschiedlich ist und Elemente hinzugefügt wurden oder entfernt wurden. Weil spätestens da kommt man rein mit Technik nicht mehr weiter, sondern muss fachlich entscheiden wann zwei Objekte das gleiche Business-Objekt referenzieren.
 

temi

Top Contributor
na, das Objekt, das den alten Wert enthält und das Objekt, was die neuen Änderungen enthält...
Kannst du nicht das "History"-Objekt direkt erstellen, wenn der Benutzer einen Wert ändert? Es gibt ja für jeden Wert ein separates History-Objekt, dass dann in die DB geschrieben wird.

Also in der Art: Ein Feld enthält einen Wert. Benutzer ändert den Wert. Du erzeugst ein Änderungsobjekt mit altem und neuen Wert. Sobald der geänderte Wert in die DB übertragen wird, schreibst du auch die Änderungsobjekte in die DB.
 
Zuletzt bearbeitet:

KonradN

Super-Moderator
Mitarbeiter
Eine Möglichkeit kann sein, dass man Änderungen erfasst, wenn diese durchgeführt wurden. Man hat ja ein Interface nach außen und wenn man Änderungen durchführt, dann merkt man sich dies. Beim Speichern muss man dann nur die erfassten Änderungen mit abspeichern und dann "löschen".

Man könnte also eine Klasse Change oder so erstellen, welche die Daten enthält wie Tabelle, Spalte, alter Wert, neuer Wert. In der Entity hat an dann eine List<Change> und in z.B. einem Setter wird dann eine neue Change Instanz erzeugt mit Klasse, Attribut, alter Wert und neuer Wert und der Liste hinzu gefügt.
 

temi

Top Contributor
Eine Möglichkeit kann sein, dass man Änderungen erfasst, wenn diese durchgeführt wurden. Man hat ja ein Interface nach außen und wenn man Änderungen durchführt, dann merkt man sich dies. Beim Speichern muss man dann nur die erfassten Änderungen mit abspeichern und dann "löschen".

Man könnte also eine Klasse Change oder so erstellen, welche die Daten enthält wie Tabelle, Spalte, alter Wert, neuer Wert. In der Entity hat an dann eine List<Change> und in z.B. einem Setter wird dann eine neue Change Instanz erzeugt mit Klasse, Attribut, alter Wert und neuer Wert und der Liste hinzu gefügt.
Irgendwie höre ich hier ein Echo ;)
 

internet

Top Contributor
Kannst nicht das "History"-Objekt direkt erstellen, wenn der Benutzer einen Wert ändert? Es gibt ja für jeden Wert ein separates History-Objekt, dass dann in die DB geschrieben wird.

Also in der Art: Ein Feld enthält einen Wert. Benutzer ändert den Wert. Du erzeugst ein Änderungsobjekt mit altem und neuen Wert. Sobald der geänderte Wert in die DB übertragen wird, schreibst du auch die Änderungsobjekte in die DB.
Doch. Das "History" - Objekt wird dann erstellt, wenn auch die Änderung durchgeführt wird.
Also sowas wie das stelle ich mir vor, wobei hier eben die Implementierung des Vergleichs fehlt und damit eine Liste<Changes> füllt.
Kann hier noch jemand helfen?

Java:
public void update(MyClass myobject){
   
    // lade derzeitiges Objekt aus der DB
    MyClass myobjectOld = loadById(myobject.getId());
   
    // Update in DB
    entityManager.merge(myobject);
   
    // Rufe Methode auf,
    saveChanges(myobjectOld, myobject)
}

public void saveChanges(Object myobjectOld, Object myobject){
   
    History history = new History();
    // Benutzer speichern, Erstellungsdatum etc. dem Objekt (lasse ich hier aber weg)
   
    entityManager.persist(history);
   
    // Erstelle HistoryValue
    checkDifferences(Object myobjectOld, Object myobject);
}

public void checkDifferences(Object myobjectOld, Object myobject){

    // Methode aufrufen, die noch fehlt
    List<Changes> list =  .......
       
    for(Changes changes : list){
        HistoryValue historyValue = new HistoryValue();
       
        // Set old Value, new Value aus dem Objekt "Changes"

        entityManager.persist(historyValue);
    }  
   
}
 

temi

Top Contributor
Also sowas wie das stelle ich mir vor, wobei hier eben die Implementierung des Vergleichs fehlt
Du musst die Änderung erfassen, wenn sie der Benutzer durchführt, also quasi, sobald er die Enter-Taste im Eingabefeld drückt. Direkt auf der Ebene des einzelnen Feldes, nicht auf der Ebene des kompletten "Datenobjektes", wie von dir gezeigt.

Es wäre sogar möglich durch den Benutzer ausschließlich diese Änderungsobjekte erzeugen zu lassen und dann aus der Liste der Änderungen einen neuen Datensatz zu generieren (das Datenobjekt), der dann komplett in die DB geschrieben wird.

Dann wird deine Methode zu update(List<ChangeObject> changes)
 

internet

Top Contributor
Du musst die Änderung erfassen, wenn sie der Benutzer durchführt, also quasi, sobald er die Enter-Taste im Eingabefeld drückt. Direkt auf der Ebene des einzelnen Feldes, nicht auf der Ebene des kompletten "Datenobjektes", wie von dir gezeigt.

Es wäre sogar möglich durch den Benutzer ausschließlich diese Änderungsobjekte erzeugen zu lassen und dann aus der Liste der Änderungen einen neuen Datensatz zu generieren (das Datenobjekt), der dann komplett in die DB geschrieben wird.

Dann wird deine Methode zu update(List<ChangeObject> changes)
ok, wäre auch ein Ansatz... aber dann reden wir auch wieder von einem ganz anderen Aufwand.

Denn dafür müsste ich dann in der GUI bei jeder Änderung (Feld, Selection Liste etc) eine Methode aufrufen, die mir die Änderung in einer Liste speichert und beim tatsächlichen Speichern zusätzlich mitgibt....
Mir würde der Vergleich der zwei Objekte reichen
 

mrBrown

Super-Moderator
Mitarbeiter
danke... glaube dann haben wir uns etwas falsch verstanden.
Wenn ich eine weitere Tabelle anlege (HistoryValue), hätte die auch so ausgesehen, nur dass ich
type, entityType, objectId herauslassen würde, da ich diese in der "Kopf Tabelle (=History)" bereits habe.
Zusätzlich käme dann eben ein FK in die Tabelle mit rein ("historyFk").

Dann hat eben eine Änderung 1....n geänderte Felder
Wie sähe denn dein geplantes Model aus, wenn du JSON/XML nutzt?
ich glaube alle haben es aktuell so verstanden, dass du in einem Datenbank-Feld ein einzelnes Objekt mit mehreren Felder speichern willst - und das ganze stumpf normalisiert ist das, was ich gezeigt hab.
 

Neumi5694

Top Contributor
Wie sieht bei dir ein "stinknormales Log" aus? In der Textdatei?

Man hat im Zugriff:
- Klassenname
- Feldname
- Alter Wert / Neuer Wert

Anschließend schreibt man eben eine Methode, die mir die Klasse holt, das Feld und schreibt dann den alten Wert wieder mittels der SET - Methode rein. Habe es nicht getestet, aber sollte so gehen.
Ja, Textdatei. formatierte Texte, bzw. JSON Einträge sind ja kein Problem.
Aber wenn du's lieber in die DB schreibst, auch gut. Eine einfache Tabelle reicht.

Zeitpunkt, User, Tabelle, Spaltenname, alter Wert, neuer Wert und was auch immer dir sonst noch an interessanten Informationen einfällt.
Da man die Zugriffe auf die DB eh alle zentralisiert macht, wird das Log genau dort geschrieben.
Sobald ein Update an einer Tabelle kommt, wird erst mal der alte Datensatz eingelesen, dann das Update geschrieben, dann kommt ins Log, welche Felder geändet wurden.
 

internet

Top Contributor
Wie sähe denn dein geplantes Model aus, wenn du JSON/XML nutzt?
ich glaube alle haben es aktuell so verstanden, dass du in einem Datenbank-Feld ein einzelnes Objekt mit mehreren Felder speichern willst - und das ganze stumpf normalisiert ist das, was ich gezeigt hab.
Tabelle History
- String type (mögliche Werte CREATE, MODIFY, DELETE)
- String für XML

XML Objekt: "HistoryValue"
- String entityType (Klassenname bzw. JPA Tabelle)
- Long objectId (ID in DB auf das Objekt)
- String fieldName (Feldname)
- String dataType (Datentyp)
- String valueOld (Wert alt)
- String valueNew (Wert neu)

Im XML String stecken dann eben 1...n HistoryValue - Objekte
Vorteil
- wäre, ich benötige keine zweite SQL Tabelle.

Nachteil
- Auswertungen auf welcher Felder sich geändert haben, wäre durch XML schwerer, da man hier immer erst das XML einlesen muss.
-> Ich tendiere daher eher es in eine SQL Tabelle zu schreiben

Folgende Probleme sehe ich noch:
1) Wie oben schon erwähnt: Methode um zwischen zwei Objekte die Unterschiede zu identifizieren
2) Bei Datentypen wie int, long, double, String sehe ich kein Problem.. Wie sieht es aber bei Referenzen aus auf andere Objekte? Wie speichere ich diese ab?
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
T Fehlercode bei code der das Alter ausrechnet Java Basics - Anfänger-Themen 2
E Alter (Laufzeit) berechnen Java Basics - Anfänger-Themen 11
K Geburtsdaten von Mehreren Personen speichern und Alter ausgeben Java Basics - Anfänger-Themen 11
N Mit LocalDate alter berechnen Java Basics - Anfänger-Themen 3
M Gerade/ungerade---alter Forenbeitrag Java Basics - Anfänger-Themen 4
G Alter berechnen Java Basics - Anfänger-Themen 9
U Alter Berechnung + sortierung Java Basics - Anfänger-Themen 6
N alter mit Date ausrechnen Java Basics - Anfänger-Themen 10
M alter einer datei Java Basics - Anfänger-Themen 6
G Alter berechnen Java Basics - Anfänger-Themen 25
V Alter mit Datum berechnen Java Basics - Anfänger-Themen 2
M hsqldb ( ALter Table test add bla VARCHAR(50) ) Java Basics - Anfänger-Themen 7
E Alter errechnen Java Basics - Anfänger-Themen 4
richis-fragen JTable den angezeigten WERT nicht den Wert aus dem Model ausgeben. Java Basics - Anfänger-Themen 3
A Negativ-Wert Java Basics - Anfänger-Themen 4
R finaler Wert in outerMethod von method in InnerMethodClass Java Basics - Anfänger-Themen 2
FunkyPhil94 Wert in einer Lambda Funktion erhöhen Java Basics - Anfänger-Themen 3
T Datum als Variable wert Java Basics - Anfänger-Themen 4
melisax Java Array Wert an bestimmtem Index angeben Java Basics - Anfänger-Themen 14
S String Array Buchstaben um einen gewissen Wert verschieben Java Basics - Anfänger-Themen 4
Ostkreuz Wert von Arrays summieren Java Basics - Anfänger-Themen 1
J Array Mittleren Wert bestimmen Java Basics - Anfänger-Themen 2
S Ausgeben wie oft ein Wert in einem Array vorkommt Java Basics - Anfänger-Themen 7
K Java gleicher Wert von Zahlen? Java Basics - Anfänger-Themen 5
M Erste Schritte While Schleife / Ausgabe von buchstabe & ASCII Wert Java Basics - Anfänger-Themen 4
M Spezifischen Wert einer Zeile aus .txt Datei entnehmen Java Basics - Anfänger-Themen 15
M Dialogbox solange abfragen, bis gültige Wert-Eingabe Java Basics - Anfänger-Themen 12
S Runden auf den niedrigsten Wert Java Basics - Anfänger-Themen 10
volcanos enum und switch (neu): falschen Wert mit IllegalArgumentException oder mit EnumConstantNotPresentException abfangen ? Java Basics - Anfänger-Themen 51
F Wie kann ich eine Funktion schreiben, die nur in bestimmten Fällen einen Wert zurückgibt? Java Basics - Anfänger-Themen 5
T Mit jedem Wert in der for-Schleife weiter arbeiten Java Basics - Anfänger-Themen 3
xaerez Threads Boolean Wert verändert sich nicht Java Basics - Anfänger-Themen 5
xaerez Threads Boolean Wert verändert sich nicht Java Basics - Anfänger-Themen 4
java-starter Erste Schritte Eingabe in Char wert umwandeln Java Basics - Anfänger-Themen 7
ravenz Schleife mit for über String Array „zahlen“und prüfen ob Wert „a“ oder „b“ oder „c“ entspricht (mittels || ) Java Basics - Anfänger-Themen 4
sserio TXT-Datei Auslesen und den Wert jedes Namen ausrechnen etc. Java Basics - Anfänger-Themen 37
M Warum return die Methode den Wert nicht Java Basics - Anfänger-Themen 5
J Wert in Dropdown Menü kursiv schrieben Java Basics - Anfänger-Themen 19
H Uhrzeitespanne in Integer Wert umrechnen Java Basics - Anfänger-Themen 1
H Java verkettete Liste, Wert eines Index zurückgeben Java Basics - Anfänger-Themen 1
M Wie kann eine Methode für ein vorhandenes "Array von char" einen Index-Wert zurückliefern? Java Basics - Anfänger-Themen 3
M Wie kann die Implementation einer Methode den Wert eines Attributs vermindern? Java Basics - Anfänger-Themen 3
M Wie kann ich festlegen, dass ein Attribut maximal den Wert 0 erreicht, also nicht in den negativen Bereich fällt? Java Basics - Anfänger-Themen 4
M Methoden Wert einer Variable geht verloren? Java Basics - Anfänger-Themen 6
U Ascii wert verschieben, wie möglich? Java Basics - Anfänger-Themen 3
B Array nach Wert prüfen rekursiv Java Basics - Anfänger-Themen 5
B in einem Array den nächstgelegenen Wert zu einem eingabewert finden Java Basics - Anfänger-Themen 8
D Einen boolischen Wert aus einer Methode in einer anderen Klasse aufrufen? Java Basics - Anfänger-Themen 11
T Algorithmus für Index mit min-Wert Java Basics - Anfänger-Themen 2
J Wert zurückgeben über get Methode Java Basics - Anfänger-Themen 8
E Slider - Wert übergeben und überschreiben Java Basics - Anfänger-Themen 5
G Input/Output getText() gibt keinen Wert! Java Basics - Anfänger-Themen 13
NaZuRe Geld(Wert) von der public static void main in die public static void Blackjack Java Basics - Anfänger-Themen 2
I Validation, ob String ein Wert aus einem Enum enthält Java Basics - Anfänger-Themen 3
J Wert in einer json Datei ändern und speichern Java Basics - Anfänger-Themen 3
S Aus verschachtelter ArrayList auf einen Wert zugreifen Java Basics - Anfänger-Themen 4
H Den Wert einer rekursiven Funktion bestimmen Java Basics - Anfänger-Themen 5
T Feststellen, dass Wert zu groß; Caesar Chiffre Java Basics - Anfänger-Themen 3
J maximaler Wert eines Integers Java Basics - Anfänger-Themen 14
I Format Problem mit Wert - bekomme 0,10 anstatt 10,00 Java Basics - Anfänger-Themen 6
H Methode über String Wert aufrufen Java Basics - Anfänger-Themen 8
G Rekursive Methode liefert augenscheinlich keinen boolean-Wert zurück. Java Basics - Anfänger-Themen 4
Lena_2611 Vergleich von Array1 Index mit Array2 Wert und erzeugen eines neues Arrays Java Basics - Anfänger-Themen 8
NeoLexx Abfrage mit instanceof führt zu unerwarteten Wert Java Basics - Anfänger-Themen 9
B Map<String, FilterMeta, wie Wert bekommen? Java Basics - Anfänger-Themen 4
ms_cikar Den Wert einer Hex. value bestimmten. Java Basics - Anfänger-Themen 8
J Eine Position im String durch einen Integer - Wert teilen Java Basics - Anfänger-Themen 5
S Integer Wert wird nicht übernommen Java Basics - Anfänger-Themen 2
V Boolean Wert nicht richtig erkannt Java Basics - Anfänger-Themen 4
H Datentypen Was für eine Format verbirgt sich hinter dem Integer-Wert 053? Java Basics - Anfänger-Themen 2
1 Array nimmt falschen Wert auf! Java Basics - Anfänger-Themen 2
S Erste Schritte Button einen Wert zuweisen & diesen ausgeben Java Basics - Anfänger-Themen 2
H Größte Duplikat (Größte Doppelte Wert) eines Arrays ausgeben Java Basics - Anfänger-Themen 9
V_Fynn03 Erste Schritte Einen Wert in ein TextField einfügen aus einer anderen Klasse Java Basics - Anfänger-Themen 3
J Wert zwischen JFrames übergeben Java Basics - Anfänger-Themen 2
J Umwandlung String zu ASCII-Wert und anders Java Basics - Anfänger-Themen 17
P Verzweigungen Wert zurück geben Java Basics - Anfänger-Themen 2
D Wert des Arrays unter Bedingungen ändern Java Basics - Anfänger-Themen 1
M Double Wert nach n abschneiden ohne zu runden Java Basics - Anfänger-Themen 1
F Boolean Methode Wert ausgeben. Java Basics - Anfänger-Themen 2
X Erste Schritte boolean wert ändert sich nicht? Java Basics - Anfänger-Themen 6
T Klassen Den Wert aus Array lesen lassen Java Basics - Anfänger-Themen 12
W Problem mit dem Wert von boolean-Variable Java Basics - Anfänger-Themen 3
J Wie kann ich z.B. einem int-Wert einen String-Wert zuweisen? Java Basics - Anfänger-Themen 2
H Einfache Frage zur Punktnotation objektname.methode(wert) Java Basics - Anfänger-Themen 2
D integer negativen Wert abspeichern Java Basics - Anfänger-Themen 3
L Wert einer Webeseiteauslesen Java Basics - Anfänger-Themen 6
D Erste Schritte Wert im Array suchen Java Basics - Anfänger-Themen 12
O Primzahl rekursiv mit einem Wert ohne i, wie? Java Basics - Anfänger-Themen 6
S Wert innerhalb eines anderen Wertes Java Basics - Anfänger-Themen 3
S Array doppelter Wert prüfen Java Basics - Anfänger-Themen 7
O Wert in einer Schleife unterschiedlich erhöhen Java Basics - Anfänger-Themen 2
B ArrayList besitzt einen Wert zu wenig Java Basics - Anfänger-Themen 16
D Compiler-Fehler Wert auf Datenbank übertragen und Sleep Thread Java Basics - Anfänger-Themen 3
F Java int-Wert wird resetet Java Basics - Anfänger-Themen 21
J Erste Schritte Wert aus JTextField zurückgeben Java Basics - Anfänger-Themen 6
CptK Bestimmten Integer Wert aus Array filtern Java Basics - Anfänger-Themen 2
B Liste von Integer -> Nächster Wert bekommen Java Basics - Anfänger-Themen 5
J Wert bei Objekterzeugung verändern Java Basics - Anfänger-Themen 12
I bestimmten Wert eines Arrays Java Basics - Anfänger-Themen 23

Ähnliche Java Themen

Neue Themen


Oben