Wenn Sie keine Zeit haben, schauen Sie sich bitte das Beispiel an
Ich habe zwei Arten von Benutzern, temporäre Benutzer und permanente Benutzer.
Temporäre Benutzer benutzen das System als Gast, geben nur ihren Namen an und benutzen ihn, aber das System muss sie verfolgen.
Dauerhafte Benutzer sind diejenigen, die registriert und dauerhaft sind.
Sobald der Benutzer einen permanenten Datensatz für sich selbst erstellt hat, muss ich alle Informationen kopieren, die verfolgt wurden, während der Benutzer ein Gast war, in seine permanente Aufzeichnung.
Klassen sind wie folgt,
%Vor%Probleme sind:
Wenn ich das tempUser-Objekt klone, kopiere ich auch die ID-Parameter, also beim Speichern des perm-Benutzerobjekts zeigt es eine Nachricht wie "Duplicate entry '10' for key ...", ich kann den tempUser nicht zuerst entfernen Speichern Sie dann den PermUser, als ob das Speichern von PermUser fehlgeschlagen ist. Ich werde die Daten verpassen. Wenn ich versuche, jeden Ball von Lieblingsstücken separat ohne ID des Gegenstands zu kopieren, wäre das kein effizienter Weg.
Beispiel ( Frage in einem Satz: Wie gezeigt, blies ein Benutzer möglicherweise mehr als einen TempUser-Datensatz und nur einen PermUser-Datensatz, daher muss ich diesem einzelnen PermUser Informationen aller TempUser-Datensätze hinzufügen aufnehmen.)
%Vor%* Bitte beachten Sie, dass ich eine Lösung finden muss, und es ist mir egal, ob Sie eine neue Lösung ausprobieren und nicht das Objekt klonen.
Der Grund, warum ich zwei verschiedene Klassen habe, ist, dass tempUser
einige zusätzliche Attribute hat, ich muss vielleicht auch Favoriten von wenigen tempUsers
zur Favoritenliste von einem permUser
hinzufügen. und auch wie oben erwähnt, kann ein Benutzer viele verschiedene nicht verwandte temporäre Datensätze haben
Verzeiht mir, wenn ich etwas verpasse, aber ich denke nicht, dass TempUser
und PermUser
unterschiedliche Klassen sein sollten. TempUser
erweitert PermUser
, was eine "ist-a" -Beziehung ist. Offensichtlich sind temporäre Benutzer keine Art von permanenten Benutzern. Ihre Frage enthält nicht genügend Informationen, um zu rechtfertigen, dass sie anders sind - vielleicht sind sie dieselbe Klasse und der Unterschied kann als ein paar neue Attribute ausgedrückt werden? ZB:
Der "Übergang" von temporär zu permanent kann von irgendeinem Controller gehandhabt werden, wobei sichergestellt wird, dass isTemporary = false
und die anderen Eigenschaften eines permanenten Benutzers entsprechend eingestellt sind. Dies würde das Cloning-Problem komplett umgehen und Ihre Datenbank erheblich vereinfachen.
Ich hatte gerade das gleiche Problem. Ich habe durch viele interessante Artikel und Fragen in Foren wie SO gegraben, bis ich genug Inspiration hatte.
Zuerst wollte ich auch Unterklassen für verschiedene Arten von Benutzern haben. Es stellt sich heraus, dass die Idee selbst ein Designfehler ist:
Verwenden Sie keine Vererbung zum Definieren von Rollen!
Weitere Informationen hier Feines Design: Vererbung gegen Rollen
Stellen Sie sich einen Benutzer als einen großen Container vor, der nur andere Entitäten wie Anmeldeinformationen, Einstellungen, Kontakte, Elemente, Benutzerinformationen usw. enthält.
In diesem Sinne können Sie die bestimmten Fähigkeiten / das Verhalten von bestimmten Benutzern einfach ändern,
Natürlich können Sie eine Rolle definieren, die viele Benutzer spielen können. Benutzer, die dieselbe Rolle spielen, haben dieselben Funktionen.
Wenn Sie viele Entitäten / Objekte haben, die voneinander abhängig sind, sollten Sie an einen Baumechanismus / ein Muster denken, der / das eine bestimmte Benutzerrolle auf eine genau definierte Weise aufbaut.
Einige Gedanken: Ein geeigneter Weg für die Instanziierung von JPA-Entitäten
Wenn Sie einen Builder / Factory für Benutzer hätten, wäre Ihr anderes Problem nicht mehr so komplex.
Beispiel (wirklich einfach, erwarte nicht zu viel!)
%Vor%Ich gebe zu, es ist etwas Arbeit, aber Sie werden viele Möglichkeiten haben, sobald Sie die Infrastruktur fertig haben! Sie können dann schnell neue Sachen "erfinden"!
Ich hoffe, ich könnte einige Ideen verbreiten. Es tut mir leid für mein elendes Englisch.
Wie ich mit früheren Kommentaren einverstanden bin, sollten Sie, wenn es möglich ist, diese Entitäten neu bewerten, aber wenn das nicht möglich ist, schlage ich vor, dass Sie einen allgemeinen Benutzer aus der Datenbank zurückgeben und diesen Benutzer entweder als PermUser oder als TempUser deklarieren Erweiterungen des Benutzers sein, basierend auf dem Vorhandensein bestimmter Kriterien.
Für Teil 2 Ihres Problems:
Sie verwenden CascadeType.ALL
für die Beziehung favorites
. Dies schließt CascadeType.REMOVE
ein, was bedeutet, dass eine Entfernungsoperation für den Benutzer zu dieser Entität kaskadieren wird. Geben Sie also ein Array von CascadeType
-Werten an, die CascadeType.REMOVE
nicht enthalten.
Siehe Ссылка .
Was ich vorschlagen werde, ist vielleicht nicht, dass OO, sondern Hoffnung wirksam sein wird. Ich bin glücklich, PermUser und TempUser getrennt zu halten, es nicht zu erweitern und sie auch nicht in eine Beziehung zu binden. Ich werde also zwei getrennte Tabellen in der Datenbank eins für TempUser und eins für PermUser haben, um sie als zwei separate Entitäten zu behandeln. Viele werden es als überflüssig empfinden .. aber lesen Sie weiter ... wir alle wissen ... manchmal ist Redundanz gut ... Also jetzt ...
1) Ich weiß nicht, wann ein TempUser zu PermUser werden soll. Also werde ich immer alle TempUsers in einer separaten Tabelle haben.
2) Was würde ich tun, wenn ein Benutzer immer TempUser sein möchte? Ich habe immer noch separate TempUser Tabelle, auf die verwiesen wird ..
3) Ich gehe davon aus, dass, wenn ein TempUser ein PermUser werden soll, Sie seinen TempUser Namen lesen, um seine Datensätze als
So, jetzt ist dein Job einfach. Wenn also ein TempUser zu PermUser werden soll, kopieren Sie einfach TempUser -Objekte, füllen Sie die erforderlichen Attribute und erstellen Sie ein neues PermUser Objekt damit. Danach können Sie Ihren TempUser Datensatz behalten, wenn Sie ihn löschen oder löschen möchten.:)
Sie hätten auch eine Geschichte, wie viele Ihrer TempUsers
tatsächlich permanent werden, wenn Sie sie behalten und auch wissen, in welcher durchschnittlichen Zeit ein TempUser
permanent wird .
Ich denke, du solltest einen manuellen tiefen Klon machen. Nicht unbedingt ein Klon, da Sie Daten von mehreren tempUsers zu einem einzigen permUser zusammenführen müssen. Sie können Reflektionen und optional Anmerkungen verwenden, um die Kopie von Informationen zu automatisieren.
Um Felder automatisch von einem vorhandenen Objekt in ein neues Objekt zu kopieren, können Sie diesem Beispiel folgen. Es ist kein tiefer Klon, aber kann Ihnen als Ausgangspunkt helfen.
Die Klasse 'c' wird als Referenz verwendet. src und dest müssen Instanzen von 'c' oder Instanzen von Unterklassen von 'c' sein. Die Methode kopiert die Attribute, die in 'c' und Superklassen von 'c' definiert sind.
%Vor%Wie einige bereits vorgeschlagen haben, würde ich dieses Problem mit Vererbung + entweder flachen Kopien (um Referenzen zu teilen) oder tiefem Klonen mit Bibliotheken, die ich ausschließen / manipulieren die automatisch generierten IDs (wenn Sie Elemente duplizieren wollen).
Da Sie Ihr Datenbankmodell nicht zu sehr verbiegen möchten, beginnen Sie mit einer Mapped Superclass mit gemeinsamen Attributen. Dies wird in Ihrer Datenbank nicht berücksichtigt. Wenn du könntest, würde ich mit Single Table Inheritance gehen, die sich deinem Modell nahe anordnet (aber möglicherweise einige Anpassungen benötigt) auf der Datenbankschicht).
%Vor% Dann müssen sowohl PermUser
als auch TempUser
von User
erben, damit sie viele gemeinsame Zustände haben:
Nun gibt es mehrere mögliche Ansätze. Wenn Ihre Klassen nicht viel Staat haben, können Sie zum Beispiel einen Konstruktor erstellen, der ein PermUser
erstellt und Daten einer Liste von TempUsers
sammelt.
Mock-Code:
%Vor% Wenn Sie PermUser
beibehalten, wird eine neue ID generiert, kaskadierte unidirektionale Beziehungen sollten funktionieren.
Andererseits, wenn Ihre Klasse viele Attribute und Beziehungen hat, und es gibt viele Situationen, in denen Sie wirklich Objekte duplizieren müssen, dann könnten Sie eine Bean Mapping-Bibliothek verwenden, zB Dozer (aber Vorsicht, das Klonen von Objekten ist ein Code-Geruch).
%Vor%Mit dem Dozer können Sie Mappings über Anmerkungen konfigurieren, API oder XML machen solche Dinge wie das Ausschließen von Feldern , Typ Casting, etc.
Mock-Mapping:
%Vor% Sie können zum Beispiel IDs ausschließen oder permUser.id
in alle geklonten bidirektionalen Beziehungen zurück zum Benutzer kopieren (falls es einen gibt), usw.
Beachten Sie außerdem, dass das Klonen von Sammlungen standardmäßig eine kumulative Operation ist.
Aus der Dozer-Dokumentation:
Wenn Sie eine Zuordnung zu einer Klasse vornehmen, die bereits initialisiert wurde, fügt Dozer der Liste entweder Objekte hinzu oder aktualisiert sie. Wenn Ihre Liste oder Ihr Set bereits Objekte in sich hat, überprüft der Dozer die zugeordnete Liste, den Satz oder das Array und ruft die contains () -Methode auf, um zu bestimmen, ob er "hinzufügen" oder "aktualisieren" muss.
Ich habe Dozer in mehreren Projekten verwendet, zum Beispiel gab es in einem Projekt eine JAXB-Schicht, die einer JPA-Modellschicht zugeordnet werden musste. Sie waren nahe genug, aber leider konnte ich mich auch nicht beugen. Dozer hat gut funktioniert, war einfach zu lernen und erspart mir 70% des langweiligen Codes. Ich kann clone diese Bibliothek aus eigener Erfahrung empfehlen.
Aus einer reinen OO-Perspektive macht es nicht wirklich Sinn, dass eine Instanz von einem Typ in einen anderen übergeht, Hibernate oder nicht. Es klingt, als ob Sie das Objektmodell unabhängig von seiner Datenbankrepräsentation überdenken möchten. FourWD scheint eher eine Eigenschaft eines Autos als eine Spezialisierung zu sein.
Eine gute Möglichkeit, dies zu modellieren, besteht darin, eine Art UserData
-Klasse zu erstellen, so dass TempUser
has-a UserData
und PermUser
has-a UserData
hat. Du könntest auch TempUser
has-a PermUser
machen, obwohl das weniger klar sein wird. Wenn Ihre Anwendung diese synonym verwenden muss (etwas, das Sie mit der von Ihnen verwendeten Vererbung erhalten würden), dann können beide Klassen eine Schnittstelle implementieren, die UserData
zurückgibt (oder in der zweiten Option getPermUser
, wo PermUser
gibt sich zurück).
Wenn Sie wirklich Vererbung verwenden möchten, ist es am einfachsten, sie mit der Tabelle "Tabelle nach Klassenhierarchie" zuzuordnen und dann direkt JDBC zu verwenden, um die Diskriminatorspalte direkt zu aktualisieren.
Tags und Links java hibernate java-ee hibernate-mapping