Kombinieren von bedingten Ausdrücken mit den Prädikaten "AND" und "OR" unter Verwendung der JPA-Kriterien-API

8

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.

%Vor%

Ein weiteres Problem: Das fkCarId ist nicht als Fremdschlüssel definiert, es ist nur eine Ganzzahl. Irgendeine Möglichkeit, um es so zu beheben?

    
Steven X 18.04.2015, 15:31
quelle

2 Antworten

17

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:

%Vor%

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.

%Vor%

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

%Vor%

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.

%Vor%

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() :

%Vor%

Die Abfrage EXISTS() :

%Vor%

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

    %Vor%

    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.

  • Ich würde vorzugsweise Joins verwenden, wenn das Ergebnis abgerufen werden soll kombiniert aus mehreren Datenbanktabellen - muss trotzdem als offensichtlich verwendet werden.

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.

    
Tiny 22.04.2015, 00:27
quelle
2

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.

    
Rick James 21.04.2015 02:27
quelle

Tags und Links