DiscriminatorColumn als Teil des Primärschlüssels / der ID

9

Situation

Ich habe eine Entität mit DiscriminatorColumn , die für die Vererbung einzelner Tabellen konfiguriert ist:

%Vor%

'ContainerAssignment' hat einen Verweis auf eine andere Entität:

%Vor%

Ein Container kann ein ContainerAssignment von jedem TYPE haben. Dies bedeutet, dass der Primärschlüssel der Tabelle ContainerAssignment durch CONTAINER_ID und TYPE definiert ist.

ContainerAssignment hat einige Unterklassen, z. B.

%Vor%

Es wird nur eine einzige SomeTypeOfContainerAssignment Instanz für eine gegebene CONTAINER_ID geben.

Problem

Wenn ich die JPA @Id nur als Container für die ContainerAssignment-Tabelle definiere, kann ich entityManager.find(SomeTypeOfContainerAssignment.class, containerId) machen, was großartig ist. Dies läuft in etwa nach SELECT * FROM CONTAINER_ASSIGNMENT WHERE CONTAINER_ID = 1 AND TYPE = 'SOME_TYPE'; . Es weiß, dass es die TYPE-Überprüfung hier wegen der @DiscriminatorValue("SOME_TYPE") Annotation auf der Entität benötigt.

Dies bedeutet jedoch, dass die Rückverweise von Container auf Container-Zuordnung abbrechen, da der Container nicht wirklich der Primärschlüssel ist. Wenn Container zum Beispiel einen @OneToOne(mappedBy=container) private SomeTypeOfContainerAssignment assignment; hat, wird beim Lesen eines Containers die Zuweisung von etwas wie SELECT * FROM CONTAINER_ASSIGNMENT WHERE CONTAINER_ID = 1; gelesen, ohne dass der Typ überprüft wird. Dies gibt ihm alle Zuweisungen für einen Container, und dann wählt er einen scheinbar zufällig aus, möglicherweise vom falschen Typ, in welchem ​​Fall er eine Ausnahme auslöst.

Wenn ich stattdessen die JPA @Id von ContainerAssignment als eine zusammengesetzte ID unter Verwendung von container und type definiere, sind Verweise auf die Unterklassen von ContainerAssignment in Ordnung.

Ich kann jedoch entityManager.find(SomeTypeOfContainerAssignment.class, containerId) nicht ausführen, da containerId nicht die ID ist. Ich muss entityManager.find(SomeTypeOfContainerAssignment.class, new MyPk(containerId, "SOME_TYPE")) machen, was den Punkt @DiscriminatorValue("SOME_TYPE") zu vereiteln scheint. Ich könnte auch nur eine einzelne ContainerAssignment-Entity verwenden, wenn ich den Typ bei der Suche trotzdem angeben muss.

Frage

Gibt es eine Möglichkeit, Arbeitsverweise auf Unterklassen einer einzelnen Tabellenvererbungs-Entität zu haben, wobei der Primärschlüssel auf der Tabelle in der Diskriminatorspalte zusammengesetzt ist, während auch EntityManager.find nur durch den / die Teil (e) möglich ist des Primärschlüssels, die nicht der Diskriminator sind?

    
Spycho 15.06.2012, 11:17
quelle

2 Antworten

0

Wenn Container eine bidirektionale OneToOne mit SomeTypeOfContainerAssignment hat, die ContainerAssignment erweitert, sollte das Containerfeld nicht in ContainerAssignment , sondern in SomeTypeOfContainerAssignment :

definiert und zugeordnet werden %Vor%

Wenn alle Arten von Containerzuordnungen eine solche OneToOne-Assoziation mit COntainer haben, können Sie den Container als

definieren %Vor%

Um ehrlich zu sein, ich weiß nicht, ob Sie die gleiche Join-Spalte in der Tabelle verwenden dürfen, um die @OneToOne container -Felder jeder Unterklasse zuzuordnen.

Ich denke, das ist das Beste, was du haben kannst. Wenn Sie das Containerfeld in die Basisklasse einfügen, müssen Sie die Zuordnung als eine OneToMany / ManyToOne-Zuordnung definieren, da dies tatsächlich der Fall ist.

Ich glaube nicht, was Sie tun wollen, und ich würde mich nicht mit zusammengesetzten PKs anlegen, da sie aus guten Gründen entmutigt werden und einen Albtraum haben.

    
JB Nizet 10.12.2012 21:48
quelle
0

Ich gehe davon aus, dass der zusammengesetzte Primärschlüssel von ContainerAssignment einwandfrei funktioniert (ich glaube wirklich, dass er JPA-abhängig sein kann!), und alles, was Sie noch stört, ist der lästige Aufruf der EntityManager.find- und PK-Instanzierung .

Meine Lösung besteht darin, Finder-Methoden unabhängig von der JPA-API zu definieren. Schliesse dich nicht an JPA. Der einfachste Weg besteht darin, einfach einen statischen Finder in Ihrer Domain-Klasse zu definieren (oder definieren Sie eine andere Klasse nur mit Findern, wenn Sie die Domain entkoppeln wollen, machen Sie JPA. Dig auf IoC, um zu wissen, wie das geht).

Bei ContainerAssignment (oder Ihrer Finder-Klasse):

%Vor%

Bei Ihrem Code:

%Vor%

Beachten Sie, dass der Typ "Teil des PK" bedeutet, dass Sie zwei ContainerAssignment-Instanzen mit unterschiedlichen Typen mit derselben ID haben können. Sie benötigen eine Abfrage, um ContainerAssignment abzurufen, wenn Sie ihren Typ nicht kennen. Wenn Ihre ID jedoch aus einer Sequenz generiert wird, können Sie einfach eine andere Finder-Methode schreiben, die die inneren Aufrufe des Entity-Frameworks ausblendet und das erste Ergebnis des Resultsets zurückgibt.

    
atorres 01.10.2015 18:15
quelle