Несколько, объединенные условия OR в ORMLite - PullRequest
11 голосов
/ 01 апреля 2012

Мне нравится иметь такой запрос:

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

В ORMlite это возможно с помощью этого кода:

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

Хотя это замечательно, если вы заранее знаете условия & atвремя кодирования, мне нужно, чтобы условия были добавлены динамически.

В принципе, этого метода 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) недостаточно.Требуется другой метод or, который поддерживает условия ArrayList из Where.

Спасибо за любые предложения.

Ответы [ 2 ]

22 голосов
/ 01 апреля 2012

Хотя это замечательно, если вы знаете условия заранее и во время кодирования, мне нужно, чтобы условия были добавлены динамически.

В ORMLite Where.or(Where<T, ID> left, Where<T, ID> right, Where<T, ID>... others) это что-то вроде синтаксического взлома.Когда вы звоните:

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

Получается метод or():

w.or(w, w);

Вы действительно можете переписать его как:

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

or метод там только с помощью аргументов, чтобы посчитать, сколько предложений ему нужно вытолкнуть из стека.Когда вы вызываете gt, lt и другие, он помещает элементы в стек предложений.Метод and() вытаскивает 1 предмет из стека, а затем забирает другой предмет в будущем.Мы делаем эти синтаксические хаки, потому что хотим поддерживать линейные, цепочечные и основанные на аргументах запросы:

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

против:

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

против:

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

Но это означает, что у вас есть возможность значительно упростить ваш код с помощью метода Where.or (int many) .Таким образом, в приведенном выше примере or также может быть:

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

Так что вам вообще не нужен список conditions.Все, что вам нужно, это счетчик.Таким образом, вы можете сделать что-то вроде:

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

Если i может быть только от 1 до 5, тогда вы можете просто использовать values.size() и пропустить clauseC.Обратите внимание, что если мы добавляем только одно предложение, то мы можем полностью пропустить вызов метода OR.

О, и следующий оператор будет не работать:

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

, потому что target и first - это один и тот же объект.first.getStatement() создает дамп всего предложения SQL WHERE, которое, я не думаю, является тем, что вам нужно.

2 голосов
/ 01 апреля 2012

Вы понимаете, что означает ... часть декларации? Это означает, что вы можете передать массив (и что компилятор создаст для вас массив, если вы просто укажете значения).

Так что, если хотите, просто создайте список, затем преобразуйте его в массив (для всех, кроме условия first ) и затем вызовите метод. Возможно, вы захотите сделать статический метод, чтобы легко выполнить последнюю часть:

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