Wie erstellt man eine generische Entity Model-Klasse, die generische ID einschließlich automatisch generierter IDs unterstützt?

8

Ich habe drei Arten von Primärschlüsseln für Tabellen:

  • INT automatisch generierter Primärschlüssel, der AUTO_INCREMENT Kapazität vom Datenbankhersteller (MySQL)
  • verwendet
  • CHAR(X) Primärschlüssel zum Speichern eines benutzerlesbaren Werts als Schlüssel (wobei X eine Zahl und 50 & lt; = X & lt; = 60)
  • ist
  • Komplexe Primärschlüssel, die aus 2 oder 3 Feldern der Tabelle bestehen.

Es gibt auch eine Gruppe von Feldern, die vorhanden sein können (oder nicht):

  • Version, INT field.
  • createdBy, VARCHAR(60) field und lastUpdatedBy, VARCHAR(60) field (es gibt mehr Felder, aber diese decken ein einfaches Beispiel ab).

Einige Beispiele für oben:

  • Tabelle1
    • id int Primärschlüssel auto_increment
    • Version int
    • Wert char (10)
    • createdBy varchar (60)
    • lastUpdatedBy varchar (60)
  • Tabelle2
    • id char (60) Primärschlüssel
    • shortDescription varchar (20)
    • longDescription varchar (100)
  • Tabelle3
    • field1 int Primärschlüssel
    • field2 int Primärschlüssel
    • Betrag dezimal (10, 5)
    • Version int

Vor diesem Hintergrund muss ich eine generische Gruppe von Klassen erstellen, die diese Anforderungen unterstützen und CRUD-Operationen mit Hibernate 4.3 und JPA 2.1 ermöglichen.

Hier ist mein aktuelles Modell (Getter / Setter vermieden, das Codebeispiel zu verkürzen):

%Vor%

Ich teste gerade Save-Instanzen von Table1 und Table2 . Ich habe den folgenden Code:

%Vor%

Beim Versuch, Table2 zu speichern, schlägt es fehl und der folgende Fehler wird angezeigt:

%Vor%

Die Fehlermeldung ist offensichtlich, weil ein CHAR(X) -Feld keinen Standardwert hat und nicht haben wird (AFAIK). Ich habe versucht, die Generierungsstrategie in GenerationType.AUTO zu ändern und habe die gleiche Fehlermeldung erhalten.

Wie kann ich diese Klassen umbauen, um diese Anforderungen zu unterstützen? Oder noch besser, wie könnte ich eine Generierungsstrategie bereitstellen, die vom Schlüssel der Entität abhängt, die ich speichere, die automatisch generiert oder von mir bereitgestellt werden kann?

Beteiligte Technologien:

  • Java SDK 8
  • Hibernate 4.3.6
  • JPA 2.1
  • MySQL- und Postgres-Datenbanken
  • Betriebssystem: Windows 7 Professional

Hinweis: Das oben Genannte kann (und wird wahrscheinlich) geändert werden, um für andere Implementierungen von JPA 2.1 wie EclipseLink unterstützt zu werden.

    
Luiggi Mendoza 29.09.2014, 21:14
quelle

3 Antworten

1

Sie können diese erzwungene abgeleitete Klasse "umgehen", um eine Methode zu implementieren, die sicherstellt, dass die ID zugewiesen ist, und diese Methode mit @PrePersist annotieren. Sie können eine Standardimplementierung für Klassen bereitstellen, für die die ID automatisch generiert wird.

Etwas wie:

%Vor%     
walkeros 09.10.2014, 06:09
quelle
5

Habe das nicht versucht, aber laut Hibernates API sollte das nicht kompliziert sein, indem man eine benutzerdefinierte Implementierung von IdentityGenerator .

Es gibt generate-Methode-gets und -Objekte, für die Sie den Wert generieren, so dass Sie den Typ des ID-Felds überprüfen und den entsprechenden Wert für Ihren Primärschlüssel zurückgeben können.

%Vor%

Wenn Sie dies einfach als Ihre Generierungsstrategie verwenden:

%Vor%

Für Hibernate 4 sollten Sie IdentifierGenerator Schnittstelle.

Wie oben für Hibernate akzeptiert, sollte es immer noch möglich sein, es generischer für jeden "jpa-kompatiblen" Provider zu erstellen. Laut JPA-API in GeneratedValue Annotation können Sie Ihren benutzerdefinierten Generator bereitstellen. Dies bedeutet, dass Sie den Namen Ihres benutzerdefinierten Generators angeben können, und Sie sollten diesen Generator für jeden jpa-Provider implementieren.

Dies würde bedeuten, dass Sie BaseEntity mit folgender Anmerkung annotieren müssen:

%Vor%

Jetzt müssen Sie einen benutzerdefinierten Generator mit dem Namen "my-custom-generator" für jeden jpa-Anbieter registrieren, den Sie verwenden möchten.

Für Hibernate wird dies durch @GenericGenerator Annotation, wie zuvor gezeigt, durchgeführt (das Hinzufügen von @GenericGenerator(name="my-custom-generator", strategy="my.package.DynamicGenerator" zu BaseEntity class auf id field oder BaseEntity class level sollte ausreichen).

In EclipseLink sehe ich, dass Sie dies über GeneratedValue Annotation erreichen können Registrierung über SessionCustomizer:

%Vor%

Jeder Anbieter muss eine Möglichkeit zur Registrierung des ID-Generators angeben. Daher müssen Sie für jeden Provider eine eigene Generierungsstrategie implementieren und registrieren, wenn Sie alle unterstützen möchten.

    
walkeros 02.10.2014 06:06
quelle
1

Vererbungshierarchien kämpfen mit ORM. Halten Sie die Dinge also einfach und bleiben Sie der Datenbankimplementierung ein wenig näher. Ordnen Sie dafür keine Hierarchie von abstrakten Oberklassen zu, sondern binden Sie annotierte POJOs für Teile von gemeinsamen Spalten ein. Sie können sich auch im restlichen Code als als nützlich erweisen .

Erstellen Sie @Embeddable classes für die freigegebenen Felder und machen Sie die Klasse für Ihre zusammengesetzte ID @Embeddable ebenfalls.

%Vor%

Die einfachste Version Ihrer Implementierungsklassen sieht dann so aus:

%Vor%

Für die String ID, keine automatische Generierung:

%Vor%

Und die zusammengesetzte ID als @EmbeddedId :

%Vor%

Als zusätzlichen Vorteil können Sie mehrere dieser Merkmale mischen und anpassen, wenn Sie möchten, da Sie nicht mehr durch die Vererbungsstruktur eingeschränkt sind.

(Sie können jedoch die Hierarchie beibehalten, die Getter und Setter sowie Standarddelegaten enthält, wenn der vorhandene Code davon abhängt und / oder davon profitiert.)

    
flup 08.10.2014 22:56
quelle