Ich muss das folgende Codebeispiel anpassen.
Ich habe eine MySQL-Abfrage, die so aussieht (2015-05-04 und 2015-05-06 sind dynamisch und symbolisieren einen Zeitbereich)
%Vor% Ich habe eine bookings
-Tabelle und eine cars
-Tabelle. Ich würde gerne herausfinden, welches Auto in einem bestimmten Zeitraum verfügbar ist. Die SQL-Abfrage funktioniert wie ein Zauber.
Ich möchte diese in eine CriteriaBuilder
-Ausgabe "konvertieren". Ich habe die Dokumentation während der letzten 3 Stunden mit dieser Ausgabe gelesen (was natürlich nicht funktioniert). Und ich habe sogar die Where Parts in den Unterabfragen übersprungen.
Ein weiteres Problem: Das fkCarId
ist nicht als Fremdschlüssel definiert, es ist nur eine Ganzzahl. Irgendeine Möglichkeit, um es so zu beheben?
Ich habe die folgenden zwei Tabellen in der MySQL-Datenbank mit nur den erforderlichen Feldern erstellt.
%Vor% booking_id
in der Tabelle bookings
ist ein Primärschlüssel und fk_car_id
ist ein Fremdschlüssel, der auf den Primärschlüssel ( car_id
) der Tabelle cars
verweist.
Die entsprechende JPA-Kriterienabfrage unter Verwendung einer IN()
-Unterabfrage funktioniert wie folgt:
Erzeugt die folgende SQL-Abfrage Ihres Interesses (getestet auf Hibernate 4.3.6 final, aber es sollte in diesem Zusammenhang keine Diskrepanz bei ORM-Frameworks geben).
%Vor% Klammern um die bedingten Ausdrücke in der WHERE
-Klausel der obigen Abfrage sind technisch völlig überflüssig, die nur für eine bessere Lesbarkeit benötigt werden, die Hibernate ignoriert - Hibernate muss sie nicht berücksichtigen.
Ich persönlich bevorzuge jedoch den Operator EXISTS
. Dementsprechend kann die Abfrage wie folgt rekonstruiert werden.
Erzeugt die folgende SQL-Abfrage.
%Vor%Das gibt die gleiche Ergebnisliste zurück.
Zusätzlich:
Hier subquery.select(criteriaBuilder.literal(1L));
, während Ausdrücke wie criteriaBuilder.literal(1L)
in komplexen Unterabfrageanweisungen auf EclipseLink verwendet werden, wird EclipseLink verwirrt und verursacht eine Ausnahme. Daher muss es möglicherweise beim Schreiben komplexer Unterabfragen in EclipseLink berücksichtigt werden. Wählen Sie einfach eine id
in diesem Fall wie
wie im ersten Fall. Hinweis: Sie sehen ein seltsames Verhalten in der SQL-Abfragegenerierung, wenn Sie einen Ausdruck wie oben in EclipseLink über die Ergebnisliste ausführen wird identisch sein.
Sie können auch Joins verwenden, die auf Backend-Datenbanksystemen effizienter sind. In diesem Fall müssen Sie DISTINCT
verwenden, um mögliche doppelte Zeilen herauszufiltern, da Sie eine Ergebnisliste aus der übergeordneten Tabelle benötigen. Die Ergebnisliste kann doppelte Zeilen enthalten, wenn mehr als eine untergeordnete Zeile in der detaillierten Tabelle vorhanden ist - bookings
für eine entsprechende übergeordnete Zeile cars
. Ich überlasse es dir. :) So geht es hier.
Erzeugt die folgende SQL-Abfrage.
%Vor% Wie zu bemerken ist, invertiert der Hibernate-Provider die bedingten Anweisungen in der WHERE
-Klausel als Antwort auf WHERE NOT(...)
. Andere Anbieter können auch das exakte WHERE NOT(...)
generieren, aber das ist das gleiche wie das in der Frage geschriebene und ergibt die gleiche Ergebnisliste wie in den vorherigen Fällen.
Rechte Joins sind nicht angegeben. Daher müssen JPA-Anbieter sie nicht implementieren. Die meisten unterstützen keine rechten Joins.
Entsprechende JPQL nur der Vollständigkeit halber:)
Die Abfrage IN()
:
Die Abfrage EXISTS()
:
Der letzte, der den linken Join verwendet (mit benannten Parametern):
%Vor%Alle oben genannten JPQL-Anweisungen können, wie Sie bereits wissen, mit der folgenden Methode ausgeführt werden.
%Vor%Ersetzen Sie die benannten Parameter mit den entsprechenden indexierten / positionsbezogenen Parametern, wenn und wann sie benötigt / benötigt werden.
Alle diese JPQL-Anweisungen generieren auch die identischen SQL-Anweisungen wie die von der Kriterien-API wie oben generiert.
Ich würde immer IN()
Sub-Abfragen in solchen Situationen vermeiden und vor allem während
mit MySQL. Ich würde IN()
sub-Abfragen verwenden, wenn und nur wenn sie es sind
absolut notwendig für Situationen wie zum Beispiel wenn wir ein
Ergebnis setzen oder löschen Sie eine Liste von Zeilen basierend auf einer Liste von statischen Werten wie
und gleich.
Ich würde in solchen Situationen immer Abfragen mit dem Operator EXISTS
bevorzugen, da die Ergebnisliste betroffen ist
nur eine einzige Tabelle basierend auf einer Bedingung in einer anderen Tabelle. Verbindet
In diesem Fall werden, wie bereits erwähnt, doppelte Zeilen erzeugt, die herausgefiltert werden müssen
Verwenden Sie DISTINCT
wie in einer der obigen Abfragen gezeigt.
Alles hängt schließlich von vielen Dingen ab. Das sind keine Meilensteine.
Haftungsausschluss: Ich habe sehr wenig Wissen über RDBMS.
Hinweis: Ich habe in allen Fällen den parametrisierten / überladenen veralteten -Datenkonstruktor - Date(String s)
für indexierte / positionale Parameter verwendet, die der SQL-Abfrage zugeordnet sind für einen reinen Testzweck nur, um das ganze Chaos von java.util.SimpleDateFormat
Rauschen zu vermeiden, das Sie bereits kennen. Sie können auch andere bessere APIs wie Joda Time (Hibernate hat Unterstützung dafür), java.sql.*
(das sind Unterklassen von java.util.Date
), Java Time in Java 8 (meist nicht unterstützt, sofern nicht angepasst) als und verwenden wenn benötigt / benötigt.
Ich hoffe, das hilft.
Es wird schneller ausgeführt, wenn Sie dieses Format verwenden:
%Vor% Dieses Formular wird immer noch nicht sehr effizient sein, da es alle cars
scannen muss, und dann einmal pro% in bookings
.
Sie benötigen einen Index für fkCarId
. "fk" riecht nach einem FOREIGN KEY
, was einen Index impliziert. Bitte geben Sie SHOW CREATE TABLE
zur Bestätigung an.
Wenn CriteriaBuilder das nicht erstellen kann, beschweren Sie sich bei ihnen oder machen Sie es Ihnen aus dem Weg.
Umdrehen könnte schneller ausgeführt werden:
%Vor% In dieser Formulierung hoffe ich, einen Tabellenscan auf bookings
durchzuführen, die reservierten Zeichen herauszufiltern und erst dann in cars
für die gewünschten Zeilen zu erreichen. Dies kann besonders schnell sein, wenn nur sehr wenige Fahrzeuge zur Verfügung stehen.