2012-08-30 7 views

Antwort

8

Da ich immer wieder darüber renne, denke ich, könnte es helfen zu klären: Erstens ist es wahr, dass Hibernate keine Diskriminierung bei der Verwendung von JOINED_TABLE Zuordnung erfordert. Bei Verwendung von SINGLE_TABLE ist dies jedoch erforderlich. Noch wichtiger ist, dass andere JPA-Anbieter es meist benötigen. Wenn Sie eine polymorphe JOINED_TABLE Abfrage ausführen, erstellen Sie einen Diskriminator mit der Bezeichnung clazz on the fly. Dabei wird ein case-switch verwendet, der das Vorhandensein von Feldern überprüft, die für konkrete Unterklassen eindeutig sind, nachdem alle an der Tabelle beteiligten Tabellen verbunden sind Vererbungsbaum Sie können dies deutlich sehen, wenn Sie die "hibernate.show_sql" Eigenschaft in Ihrem persistence.xml einschließen. Aus meiner Sicht ist dies wahrscheinlich die perfekte Lösung für JOINED_TABLE Abfragen, so dass die Hibernate-Leute sind richtig, damit zu prahlen.

Die Sache ist etwas anders, wenn Updates und Löschungen durchgeführt werden; Hier fragt Hibernate zuerst Ihre Root-Tabelle nach Schlüsseln ab, die der where-Klausel der Anweisung entsprechen, und erstellt aus dem Ergebnis ein virtuelles pkTable. Dann führt es eine "DELETE FROM/UPDATE table WHERE pk IN pkTable" für jede konkrete Klasse mit Ihrem Vererbungsbaum durch; Der IN-Operator bewirkt, dass eine O(log(N)) Unterabfrage pro Tabelleneintrag gescannt wird, aber es ist wahrscheinlich im Arbeitsspeicher, daher ist es aus Leistungsperspektive nicht schlecht.

Um Ihre spezifische Frage zu beantworten, sieht Hibernate hier einfach kein Problem und aus einer bestimmten Perspektive sind sie korrekt. Es wäre unglaublich einfach für sie, die @DiscriminatorValue Annotationen einfach durch Injizieren der Diskriminatorwerte während entityManager.persist() zu ehren, selbst wenn sie sie nicht tatsächlich verwenden. Die Unterscheidung der Diskriminatorspalte in JOINED_TABLE hat jedoch nicht den Vorteil (für Hibernate), einen milden Fall von Vendor Lockin zu erzeugen, und es ist sogar vertretbar, indem auf überlegene Technologie verwiesen wird.

@ForceDiscriminator oder @DiscriminatorOptions(force=true) sicher helfen, den Schmerz ein wenig zu mildern, aber Sie müssen sie verwenden, bevor die ersten Entitäten erstellt werden, oder gezwungen werden, die fehlenden Diskriminatorwerte manuell mithilfe von SQL-Anweisungen hinzuzufügen. Wenn Sie es wagen, sich von Hibernate zu entfernen, kostet es Sie zumindest einige Codeänderungen, um diese Hibernate-spezifischen Annotationen zu entfernen, wodurch Widerstand gegen die Migration entsteht. Und das ist offensichtlich alles, woran sich Hibernate in diesem Fall interessiert.

Meiner Erfahrung nach ist Vendor Lockin das Paradies, von dem die wildesten Träume jedes Marktführers handeln, denn es ist der machiavellistische Zauberstab, der den Marktanteil ohne Anstrengung schützt. es wird also immer dann gemacht, wenn Kunden sich nicht wehren und dem Verkäufer einen Preis auferlegen, der höher ist als die geerntete Leistung. Wer hat gesagt, dass eine Open-Source-Welt anders wäre?

p.s, nur um Verwirrung zu vermeiden: Ich bin in keiner Weise mit einem JPA-Implementierer verbunden.

pp.s: Was ich normalerweise tue, ist das Problem bis zur Migrationszeit zu ignorieren; Sie können dann eine SQL UPDATE ... FROM-Anweisung mit demselben Case-Switch-mit-Outer-Joins-Trick formulieren, den Hibernate verwendet, um die fehlenden Diskriminatorwerte auszufüllen. Es ist eigentlich ganz einfach, wenn man das Grundprinzip verstanden hat.

2

Ich denke, das ist mehr meiner Meinung, aber ich denke, einige werden mir zustimmen. Ich bevorzuge die Tatsache, dass Hibernate es Ihnen ermöglicht, keinen Diskriminator zu verwenden. In einigen Fällen ist der Diskriminator nicht notwendig.

Zum Beispiel, ich habe eine Person Einheit, die Sachen wie ein Name enthält, ein Geburtsdatum, usw. Diese Einheit kann durch verschiedene andere Einrichtungen wie Employee oder Customer verwendet werden. Wenn ich nicht auf Person von anderen Entitäten referenziere, sondern stattdessen auf oder Customer, wird der Diskriminator nicht verwendet, da Hibernate angewiesen wird, einen zu holen.

+0

Guter Punkt, aber immer noch gibt es Fälle, in denen Hibernate einfach nicht (WrongClassException) arbeiten. Warum funktioniert der Ruhezustand nicht ohne Kraftaufwand? – yannisf

+0

@yannisf Ich glaube, das hängt von deinem Code/Design ab. Ich habe Hibernate mehrmals ohne Diskriminatoren benutzt und hatte dieses Problem nie. – siebz0r

3

Jungs lassen Sie mich versuchen, über @DiscriminatorOptions(Force=true) zu erklären. Nun, es ist in Single-Table-Vererbung verwendet, ich habe kürzlich in einem der Szenario verwendet. Ich habe zwei Entitäten, die auf einzelne Tabelle zugeordnet wurde. Als ich versuchte, den Datensatz für eine Entität abzurufen, erhielt ich eine Liste mit Ergebnissen, die Datensätze von beiden Entitäten enthielten, und das war mein Problem. Um dieses Problem zu lösen, habe ich @DiscriminatorOptions(Force=true) verwendet, das das Prädikat mit der Diskriminator-Spalte mit dem angegebenen Wert erstellen wird, der der entsprechenden Entität zugeordnet ist. so wird die Abfrage wie folgt aussehen werden, nachdem ich @DiscriminatorOptions(Force=true) verwendet

select * 
from TABLE 
where YOUR PREDICATE AND DiscriminatorColumn = DiscriminatorValue 
-1

@yannisf ForceDiscriminator ist nicht die einzige Lösung, um dieses Problem zu lösen.

Sie können für jedes Kind Klasse Instanceof Tests durchführen. Dies ist zwar so, als würden Sie Ihre Klassen in Ihrem Code hart codieren, aber es ist eine sauberere Methode, das Problem zu lösen, wenn die Diskriminatorspalte nicht gefüllt ist.

Dies hilft auch Ihrem Code zu vermeiden, jpa und Hibernate Annotationen zu mischen.

Wie von yannisf hervorgehoben, ist instanceOf eine Art Antipattern in der OO-Welt.

Eine andere Lösung könnte Ihre Entitätszuordnung werden zu ändern. Angenommen, eine Entität A verweist auf eine Superklasse B, und B hat untergeordnete Klassen vom Typ C1 und C2. Statt A auf B zu zeigen, können Sie C1 und C2 einen Fremdschlüssel auf A zeigen lassen. Es kommt darauf an, sich zu ändern das Entity-Design, um Anmerkungen nicht zu mischen.

Dank Vaibhav

+0

Vielen Dank für Ihren Kommentar. instanceOf hat sich in Bezug auf dynamische Proxies (siehe Lazy Loading) als sehr unzuverlässiges Werkzeug erwiesen. Darüber hinaus ist instanceOf ein Design-Antipattern in der OO-Welt. Schließlich müsste man eine willkürliche Logik codieren, um über die tatsächliche Klassenauflösung zu entscheiden. – yannisf

Verwandte Themen