2012-04-01 7 views
10

Ich mag eine Abfrage wie diese haben:Multiple, kombinierte oder Bedingungen in ORMLite

select data from table 
where (x > 1 and x < 100) 
    or (x > 250 and x < 300) 

In ORMlite, das ist möglich, diesen Code verwenden:

final QueryBuilder<Data,Integer> qb = queryBuilder(); 
final Where<Data, Integer> w = qb.where(); 

w.or(
    w.gt("x", 1).and().lt("x", 100), 
    w.gt("x", 250).and().lt("x", 300) 
) 

Während das ist toll, wenn man die Bedingungen kennt vorher & zum Zeitpunkt der Codierung muss ich die Bedingungen dynamisch hinzugefügt werden.

Grundsätzlich ist diese Methode public com.j256.ormlite.stmt.Where<T,ID> or(com.j256.ormlite.stmt.Where<T,ID> left, com.j256.ormlite.stmt.Where<T,ID> right, com.j256.ormlite.stmt.Where<T,ID>... others) nicht genug. Es benötigt eine andere or Methode, die eine ArrayList von Where Bedingungen unterstützt.

Vielen Dank für Anregungen.

Antwort

20

In ORMLiteWhere.or(Where<T, ID> left, Where<T, ID> right, Where<T, ID>... others) ein bisschen eine Syntax Hack ist. Wenn Sie anrufen:

w.or(
    w.gt("x", 1).and().lt("x", 100), 
    w.gt("x", 250).and().lt("x", 300) 
); 

Was die or() Methode bekommt, ist:

w.or(w, w); 

Sie es wirklich so umschreiben könnte:

w.gt("x", 1).and().lt("x", 100); 
w.gt("x", 250).and().lt("x", 300); 
w.or(w, w); 

Die or Methode nur die Argumente verwendet zu zählen Wie viele Klauseln braucht es, um vom Stapel zu springen. Wenn Sie gt und lt und andere aufrufen, verschiebt es Elemente auf einem Klauselstapel. Die Methode and() zieht 1 Element vom Stapel und nimmt dann in der Zukunft ein anderes Element. Wir tun diese Hacks Syntax, weil wir linear unterstützen wollen, angekettet, und das Argument basierte Abfragen:

w.gt("x", 1); 
w.and(); 
w.lt("x", 100); 

gegen:

w.gt("x", 1).and().lt("x", 100); 

gegen:

w.and(w.gt("x", 1), w.lt("x", 100)); 

Aber das bedeutet, dass Sie die Macht, Ihren Code immens zu vereinfachen, indem Sie die Methode Where.or(int many) verwenden. So in dem or obigen Beispiel kann auch sein:

w.gt("x", 1).and().lt("x", 100); 
w.gt("x", 250).and().lt("x", 300); 
// create an OR statement from the last 2 clauses on the stack 
w.or(2); 

So brauchen Sie nicht die conditions Liste aller bei. Alles was Sie brauchen ist ein Zähler.So könnte man so etwas wie:

int clauseC = 0; 
for (int i : values) { 
    if (i == 1) { 
     w.le(C_PREIS, 1000); 
     clauseC++; 
    } else if (i == 2) { 
     w.gt(C_PREIS, 1000).and().le(C_PREIS, 2500); 
     clauseC++; 
    } else if (i == 3) { 
     w.gt(C_PREIS, 2500).and().le(C_PREIS, 5000); 
     clauseC++; 
    } else if (i == 4) { 
     w.gt(C_PREIS, 5000).and().le(C_PREIS, 10000); 
     clauseC++; 
    } else if (i == 5) { 
     w.gt(C_PREIS, 10000); 
     clauseC++; 
    } 
} 
// create one big OR(...) statement with all of the clauses pushed above 
if (clauseC > 1) { 
    w.or(clauseC); 
} 

Wenn i nur 1 bis 5 sein kann, dann können Sie nur values.size() verwenden und die clauseC überspringen. Beachten Sie, dass wir den Methodenaufruf OR vollständig überspringen können, wenn wir nur eine Klausel hinzufügen.

Oh, und die folgende Anweisung wird nicht Arbeit:

target.or().raw(first.getStatement()); 

weil target und first sind das gleiche Objekt. first.getStatement() Dumps die gesamte SQL WHERE Klausel, die ich glaube nicht, was Sie wollen.

+0

Das funktioniert fantastisch! Danke für die Hintergrundinformationen zu ORMlite und die Erklärung und Hilfe. Glücklich Code und Komplexität entfernen. Vielen Dank! –

+1

Ich bin froh, Sebastian zu helfen. Ich war wirklich entsetzt, dass @Jon die Antwort einer ORMLite-Frage versuchte. Der einzige Grund, warum ich überhaupt Punkte bekomme, sind ORMLite-Fragen. Seine Antworten sind normalerweise so großartig. :-) Seien Sie sicher, Ihre Frage zu redigieren und die "veralteten" Abschnitte jetzt zu entfernen oder zu korrigieren. – Gray

2

Verstehen Sie, was der ... Teil der Deklaration bedeutet? Das bedeutet, dass Sie ein Array übergeben können (und dass der Compiler ein Array für Sie erstellt, wenn Sie nur Werte angeben).

So erstellen Sie einfach eine Liste, wenn Sie möchten, dann konvertieren Sie es in ein Array (für alle außer der ersten Bedingung) und rufen Sie dann die Methode. Sie können auch eine statische Methode machen wollen, den letzten Teil leicht zu tun:

public static <T, ID> void or(Where<T, ID> target, 
           List<Where<T, ID>> conditions) 
{ 
    // TODO: Argument validation 
    Where<T, ID> first = conditions.get(0); 
    Where<T, ID> second = conditions.get(1); 
    List<Where<T, ID>> rest = conditions.subList(2, conditions.size()); 
    // You'll to suppress a warning here due to generics... 
    Where<T, ID>[] restArray = rest.toArray(new Where[0]); 
    target.where(first, second, restArray); 
} 
+0

Argh, wie könnte ich das vermissen. ;) Danke, Jon. Ich habe dein Beispiel ausprobiert und jetzt heißt es: 'kann die Symbolmethode oder (com.j256.ormlite.stmt.Where , com.j256.ormlite.stmt.Where [])' im 'target.where' Teil nicht finden . –

+0

@SebastianRoth: Okay, sieht so aus, als hätte ich die Signatur falsch gelesen - es ist ein * dritter * Parameter. Gleiche Idee. Wird bearbeiten ... –

+0

Dank Jon, im Grunde ist Ihr Vorschlag in der richtigen Weise. Ich sehe, das ist viel komplizierter als es sein sollte. Die Idee wird nicht richtig funktionieren, wenn nur ein Element vorhanden ist, oder nur zwei usw. Ich werde bearbeiten und meine Version dort hinstellen. Dies scheint eine Änderung in ORMlite zu erfordern. –