2012-04-01 11 views
10

Me gustaría tener una consulta como esta:múltiples, las condiciones combinada o en ORMLite

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

En ORMlite, eso es posible utilizar este código:

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

Mientras que eso es genial si uno conoce las condiciones de antemano & en el momento de la codificación, necesito que las condiciones se agreguen dinámicamente.

Básicamente, el método 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) no es suficiente. Necesita otro método or que admita un ArrayList de Where condiciones.

Gracias por cualquier sugerencia.

Respuesta

20

En ORMLiteWhere.or(Where<T, ID> left, Where<T, ID> right, Where<T, ID>... others) es un poco de un truco de sintaxis. Cuando se llama:

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

Lo que el método or() obtiene es:

w.or(w, w); 

Realmente podría reescribir como:

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

El método or no es sólo con los argumentos de contar Cuántas cláusulas necesita para salir de la pila. Cuando llama al gt y lt y otros, empuja los elementos en una pila de cláusulas. El método and() saca 1 elemento de la pila y luego toma otro artículo en el futuro. Hacemos estas cortes de sintaxis porque queremos apoyar lineal, encadenado, y en base de argumentos consultas:

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

frente:

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

frente:

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

Pero esto significa que usted tiene el poder de simplificar inmensamente su código utilizando el método Where.or(int many). Así, en el ejemplo anterior or también puede ser:

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

por lo que no necesitan la lista conditions en absoluto. Todo lo que necesitas es un contador.Por lo que podría hacer algo como:

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

Si i sólo puede ser de 1 a 5 a continuación, puedes utilizar values.size() y omitir el clauseC. Tenga en cuenta que si solo agregamos una cláusula, podemos omitir la llamada al método OR por completo.

Ah, y la siguiente declaración le no trabajo:

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

porque target y first son el mismo objeto. first.getStatement() vuelca la cláusula SQL WHERE que no creo que sea lo que desea.

+0

¡Eso funciona fantástico! Gracias por la información de fondo sobre ORMlite y la explicación y ayuda. Felizmente eliminando código y complejidad. ¡Gracias! –

+1

Feliz de ayudar a Sebastian. De hecho, me horroricé de que @Jon probara la respuesta como una pregunta ORMLite. La única razón por la que obtengo algún punto es por las preguntas de ORMLite. Sus respuestas son generalmente tan geniales. :-) Asegúrese de editar su pregunta y eliminar o corregir las secciones "Resueltas" ahora desactualizadas. – Gray

2

¿Entiende lo que significa la parte ... de la declaración? Significa que puede pasar una matriz (y que el compilador construirá una matriz para usted si solo especifica valores).

Así que solo cree una lista si lo desea, luego conviértala en una matriz (para todas menos primera condición) y luego llame al método. Usted también puede querer hacer un método estático que hacer la última parte fácil:

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, cómo podría extrañar eso. ;) Gracias Jon. Probé tu ejemplo y en este momento dice: 'no se puede encontrar el método del símbolo o (com.j256.ormlite.stmt.Where , com.j256.ormlite.stmt.Where [])' en la parte 'target.where' . –

+0

@SebastianRoth: De acuerdo, parece que leí mal la firma, es un * tercer * parámetro. La misma idea sin embargo. Editará ... –

+0

Gracias Jon, básicamente tu sugerencia es correcta. Veo que esto es mucho más complicado de lo que debería ser. La idea no funcionará correctamente si solo hay un elemento, o solo dos, etc. Editaré y pondré mi versión allí. Esto parece necesitar un cambio en ORMlite. –

Cuestiones relacionadas