2012-01-09 28 views
52

Tôi có một truy vấn LINQ trông giống như sau:khoản Nhiều WHERE với phương pháp khuyến nông LINQ

DateTime today = DateTime.UtcNow; 
var results = from order in context.Orders 
       where ((order.OrderDate <= today) && (today <= order.OrderDate)) 
       select order; 

tôi đang cố gắng để tìm hiểu/hiểu LINQ. Trong một số trường hợp, tôi cần thêm hai mệnh đề WHERE bổ sung. Để thực hiện điều này, tôi đang sử dụng:

if (useAdditionalClauses) 
{ 
    results = results.Where(o => o.OrderStatus == OrderStatus.Open) // Now I'm stuck. 
} 

Như bạn có thể thấy, tôi biết cách thêm mệnh đề WHERE bổ sung. Nhưng làm thế nào để tôi thêm nhiều? Ví dụ: tôi muốn thêm

WHERE o.OrderStatus == OrderStatus.Open AND o.CustomerID == customerID

vào truy vấn trước đó của tôi. Làm thế nào để tôi làm điều này bằng cách sử dụng các phương pháp mở rộng?

Cảm ơn bạn!

Trả lời

101

Hai cách:

results = results.Where(o => (o.OrderStatus == OrderStatus.Open) && 
          (o.CustomerID == customerID)); 

hay:

results = results.Where(o => (o.OrderStatus == OrderStatus.Open)) 
       .Where(o => (o.CustomerID == customerID)); 

Tôi thường thích thứ hai. Nhưng nó có giá trị profiling máy chủ SQL để kiểm tra thực hiện truy vấn và xem cái nào thực hiện tốt hơn cho dữ liệu của bạn (nếu có bất kỳ sự khác biệt nào cả).

Lưu ý về chuỗi các phương pháp .Where(): Bạn có thể kết hợp tất cả các phương pháp LINQ mà bạn muốn. Các phương thức như .Where() không thực sự thực thi đối với cơ sở dữ liệu (chưa). Họ defer execution cho đến khi kết quả thực tế được tính toán (chẳng hạn như với .Count() hoặc .ToList()). Vì vậy, khi bạn kết nối nhiều phương thức với nhau (nhiều cuộc gọi hơn đến .Where(), có thể là .OrderBy() hoặc thứ gì đó có hiệu lực đó, v.v.) chúng sẽ tạo nên cái gọi là expression tree. Toàn bộ cây này là những gì được thực thi dựa trên nguồn dữ liệu khi thời gian đến để đánh giá nó.

+0

Tôi cảm thấy câm khi không biết tôi có thể làm được điều này .. Bạn vừa mới cứu tôi khỏi rất nhiều mã spaghetti. – ledgeJumper

+0

Cảm ơn, Điều đó đã giúp tôi. Nhưng nó cũng có thể là tôi sẽ kích hoạt bất kỳ một trong các khoản khoản phụ thuộc vào một biến nhất định? @David –

0

Chỉ cần sử dụng toán tử && giống như với bất kỳ câu lệnh nào khác mà bạn cần thực hiện logic boolean.

if (useAdditionalClauses) 
{ 
    results = results.Where(
        o => o.OrderStatus == OrderStatus.Open 
        && o.CustomerID == customerID)  
} 
3

Chắc chắn:

if (useAdditionalClauses) 
{ 
    results = 
    results.Where(o => o.OrderStatus == OrderStatus.Open && 
    o.CustomerID == customerID) 
} 

Hoặc chỉ là một .Where() gọi như thế này (mặc dù tôi không biết lý do tại sao bạn muốn, trừ khi nó được chia bởi một biến kiểm soát boolean):

if (useAdditionalClauses) 
{ 
    results = results.Where(o => o.OrderStatus == OrderStatus.Open). 
    Where(o => o.CustomerID == customerID); 
} 

Hoặc chuyển nhượng lại cho results: `results = results.Where (blah).

14

Bạn có thể tiếp tục chuỗi chúng như bạn đã làm.

results = results.Where (o => o.OrderStatus == OrderStatus.Open); 
results = results.Where (o => o.InvoicePaid); 

Điều này đại diện cho AND.

+0

Bạn - và những người khác - đánh bại tôi quá, nhưng đây có lẽ là cách dễ đọc nhất để làm điều đó. –

+4

Lặp lại các mệnh đề được thêm vào truy vấn với toán tử "và" ở giữa. – linkerro

+0

Đây có lẽ không phải là giải pháp 'sạch' nhất, nhưng trong trường hợp của tôi, đây là giải pháp duy nhất hoạt động cho đến nay. Tôi đã phải thêm mệnh đề 'where' dựa trên các lựa chọn trong giao diện người dùng. –

1
results = context.Orders.Where(o => o.OrderDate <= today && today <= o.OrderDate) 

Lựa chọn này không được thực hiện khi bạn đang làm việc với đơn đặt hàng.

2

bạn có thể sử dụng & & và viết tất cả các điều kiện vào cùng một điều khoản, hoặc bạn có thể .Where(). Where(). Where() ... v.v.

7

Nếu bạn làm việc với trong bộ nhớ dữ liệu (đọc "bộ sưu tập của poco"), bạn cũng có thể ngăn xếp biểu thức của bạn với nhau sử dụng PredicateBuilder như vậy:

// initial "false" condition just to start "OR" clause with 
var predicate = PredicateBuilder.False<YourDataClass>(); 

if (condition1) 
{ 
    predicate = predicate.Or(d => d.SomeStringProperty == "Tom"); 
} 

if (condition2) 
{ 
    predicate = predicate.Or(d => d.SomeStringProperty == "Alex"); 
} 

if (condition3) 
{ 
    predicate = predicate.And(d => d.SomeIntProperty >= 4); 
} 

return originalCollection.Where<YourDataClass>(predicate.Compile()); 

Nguồn đầy nêu PredicateBuilder là dưới đây (nhưng bạn cũng có thể kiểm tra original page với một vài ví dụ khác):

using System; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Collections.Generic; 

public static class PredicateBuilder 
{ 
    public static Expression<Func<T, bool>> True<T>() { return f => true; } 
    public static Expression<Func<T, bool>> False<T>() { return f => false; } 

    public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1, 
                 Expression<Func<T, bool>> expr2) 
    { 
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression>()); 
    return Expression.Lambda<Func<T, bool>> 
      (Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters); 
    } 

    public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1, 
                 Expression<Func<T, bool>> expr2) 
    { 
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression>()); 
    return Expression.Lambda<Func<T, bool>> 
      (Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters); 
    } 
} 

Note: tôi đã thử nghiệm phương pháp này với dự án Portable Class Library và hav e sử dụng .Compile() để làm cho nó làm việc:

đâu (vị .Compile());

+0

Có một lý do tại sao điều này sẽ không làm việc với Entity Framework LINQ? – Ciantic

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