2012-04-01 23 views
10

Tôi muốn có một truy vấn như thế này:Nhiều, điều kiện kết hợp OR trong ORMLite

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

Trong ORMlite, đó là có thể sử dụng mã này:

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

Trong khi thats tuyệt vời nếu ai biết các điều kiện trước đây & tại thời điểm mã hóa, tôi cần các điều kiện được thêm động.

Về cơ bản, phương pháp 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) là không đủ. Cần có phương thức or khác hỗ trợ điều kiện ArrayList của Where.

Cảm ơn mọi đề xuất.

Trả lời

20

Trong ORMLiteWhere.or(Where<T, ID> left, Where<T, ID> right, Where<T, ID>... others) là một chút của một cú pháp hack. Khi bạn gọi:

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

gì phương pháp or() được là:

w.or(w, w); 

Bạn thực sự có thể viết lại nó như:

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

Các or phương pháp chỉ có đang sử dụng các đối số để đếm có bao nhiêu mệnh đề cần bật ra khỏi ngăn xếp. Khi bạn gọi gtlt và các thiết bị khác, nó sẽ đẩy các mục trên ngăn xếp khoản. Phương pháp and() kéo 1 mục ra khỏi ngăn xếp và sau đó lấy một mục khác trong tương lai. Chúng tôi làm những hacks cú pháp bởi vì chúng tôi muốn hỗ trợ tuyến tính, xiềng xích, và các truy vấn tham số dựa trên:

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

so:

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

so:

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

Nhưng điều này có nghĩa là bạn có sức mạnh để đơn giản hóa mã của bạn vô cùng bằng cách sử dụng phương thức Where.or(int many). Vì vậy, trong ví dụ or trên cũng có thể là:

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

Vì vậy, bạn không cần danh sách conditions ở tất cả. Tất cả những gì bạn cần là một bộ đếm.Vì vậy, bạn có thể làm điều gì đó như:

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

Nếu i chỉ có thể là 1-5 sau đó bạn chỉ có thể sử dụng values.size() và bỏ qua clauseC. Lưu ý rằng nếu chúng ta chỉ thêm một mệnh đề thì chúng ta có thể bỏ qua toàn bộ cuộc gọi phương thức OR.

Oh, và tuyên bố sau sẽ không công việc:

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

targetfirst là cùng một đối tượng. first.getStatement() bãi toàn bộ mệnh đề SQL WHERE mà tôi không nghĩ là những gì bạn muốn.

+0

Điều đó hoạt động tuyệt vời! Cảm ơn thông tin cơ bản về ORMlite và giải thích và trợ giúp. Vui lòng xóa mã và độ phức tạp. Cảm ơn bạn! –

+1

Vui lòng giúp Sebastian. Tôi đã thực sự kinh hoàng rằng @Jon đã thử câu trả lời một câu hỏi ORMLite. Lý do duy nhất tại sao tôi nhận được bất kỳ điểm nào là từ câu hỏi ORMLite. Câu trả lời của anh ta thường rất tuyệt. :-) Hãy chắc chắn chỉnh sửa câu hỏi của bạn và xóa hoặc sửa các phần "Đã giải quyết" đã lỗi thời. – Gray

2

Bạn có hiểu phần ... của bản khai có nghĩa là gì không? Nó có nghĩa là bạn có thể vượt qua trong một mảng (và trình biên dịch sẽ xây dựng một mảng cho bạn nếu bạn chỉ định các giá trị).

Vì vậy, chỉ cần tạo danh sách nếu bạn muốn, sau đó chuyển đổi nó thành một mảng (cho tất cả trừ điều kiện đầu tiên) và sau đó gọi phương thức. Bạn cũng có thể muốn thực hiện một phương pháp tĩnh để làm phần cuối cùng dễ dàng:

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, làm thế nào tôi có thể bỏ lỡ điều đó. ;) Cảm ơn Jon. Tôi đã thử ví dụ của bạn và ngay bây giờ nó nói: 'không thể tìm thấy phương thức biểu tượng hoặc (com.j256.ormlite.stmt.Where , com.j256.ormlite.stmt.Where [])' tại phần 'target.where' . –

+0

@SebastianRoth: Ok, có vẻ như tôi đã đọc sai chữ ký - đó là thông số * thứ ba *. Cùng một ý tưởng mặc dù. Sẽ chỉnh sửa ... –

+0

Cảm ơn Jon, về cơ bản đề xuất của bạn là đúng cách. Tôi thấy điều này phức tạp hơn nhiều so với nó. Ý tưởng sẽ không hoạt động đúng nếu chỉ có một phần tử ở đó, hoặc chỉ có hai phần tử, vv. Tôi sẽ chỉnh sửa và đặt phiên bản của mình ở đó. Điều này dường như cần một sự thay đổi trong ORMlite. –

Các vấn đề liên quan