2012-04-01 15 views
10

mi piace avere una query come questa:multipli, condizioni combinate o in ORMLite

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

In ORMlite, questo è possibile utilizzando questo codice:

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

Mentre questo è grande se si sa le condizioni in anticipo & al momento della codifica, ho bisogno che le condizioni vengano aggiunte dinamicamente.

Fondamentalmente il metodo 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) non è sufficiente. È necessario un altro metodo or che supporti una condizione ArrayList di Where.

Grazie per eventuali suggerimenti.

risposta

20

In ORMLiteWhere.or(Where<T, ID> left, Where<T, ID> right, Where<T, ID>... others) è un po 'di hack sintassi. Quando si chiama:

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

ciò che il metodo or() ottiene è:

w.or(w, w); 

si potrebbe davvero riscrivere come:

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

Il metodo or c'è solo utilizzando gli argomenti a contare quante clausole ha bisogno di uscire dalla pila. Quando chiami gt e lt e altri, inserisce elementi in una pila di clausole. Il metodo and() estrae 1 elemento dallo stack e quindi prende un altro elemento in futuro. Facciamo questi hack di sintassi perché vogliamo sostenere lineari, incatenato, e argomento basato query:

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

rispetto:

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

versus:

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

Ma questo significa che è necessario il potere di semplificare immensamente il tuo codice utilizzando il metodo Where.or(int many). Quindi, nell'esempio or sopra può anche essere:

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); 

Quindi non occorre la lista conditions a tutti. Tutto ciò di cui hai bisogno è un contatore.Così si potrebbe fare qualcosa di simile:

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); 
} 

Se i non può che essere da 1 a 5, allora si può solo usare values.size() e saltare il clauseC. Si noti che se stiamo aggiungendo solo una clausola, possiamo saltare interamente la chiamata al metodo OR.

Oh, e la seguente dichiarazione sarà non lavoro:

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

perché target e first sono lo stesso oggetto. first.getStatement() scarica l'intera clausola SQL WHERE che non penso sia ciò che desideri.

+0

Che funziona fantastico! Grazie per le informazioni di base su ORMlite e la spiegazione e l'aiuto. Rimuovendo felicemente il codice e la complessità. Grazie! –

+1

Felice di aiutare Sebastian. Sono stato davvero inorridito dal fatto che @Jon abbia provato la risposta con una domanda ORMLite. L'unico motivo per cui ottengo alcun punto è da domande ORMLite. Le sue risposte sono solitamente così grandi. :-) Assicurati di modificare la tua domanda e rimuovere o correggere le sezioni "Risolto" non aggiornate. – Gray

2

Capisci cosa significa la parte ... della dichiarazione? Significa che puoi passare in un array (e che il compilatore costruirà un array per te se specifichi solo i valori).

Quindi è sufficiente creare un elenco se lo si desidera, quindi convertirlo in un array (per tutti tranne la condizione prima) e quindi chiamare il metodo. Si può ben desidera rendere un metodo statico di fare l'ultima parte facilmente:

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, come potrei mancarlo. ;) Grazie Jon. Ho provato il tuo esempio e ora dice: 'impossibile trovare il metodo simbolo o (com.j256.ormlite.stmt.Where , com.j256.ormlite.stmt.Where [])' nella parte 'target.where' . –

+0

@SebastianRoth: Ok, sembra che ho letto male la firma: è un * terzo * parametro. La stessa idea però. Modificherà ... –

+0

Grazie Jon, in pratica il tuo suggerimento è nel modo giusto. Vedo che questo è molto più complicato di quanto dovrebbe essere. L'idea non funzionerà correttamente se solo un elemento è presente, o solo due ecc. Io modificherò e inserirò la mia versione lì. Questo sembra aver bisogno di un cambiamento in ORMlite. –