Nhiều mệnh đề WHERE với các phương thức mở rộng LINQ


79

Tôi có một truy vấn LINQ trông giống như sau:

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 học / hiểu LINQ. Trong một số trường hợp, tôi cần thêm hai mệnh đề WHERE bổ sung. Trong một nỗ lực để làm đ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 thấy, tôi biết cách thêm một mệnh đề WHERE bổ sung. Nhưng làm cách nào để thêm nhiều? Ví dụ, tôi muốn thêm

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

cho truy vấn trước đó của tôi. Làm cách nào để thực hiện việc này bằng các phương pháp mở rộng?

Cảm ơn bạn!

Câu trả lời:


151

Hai lối:

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

hoặc là:

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

Tôi thường thích cái sau hơn. Nhưng nó đáng để cấu hình máy chủ SQL để kiểm tra việc thực thi truy vấn và xem cái nào hoạt động 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).

Lưu ý về chuỗi các .Where()phương thức: Bạn có thể chuỗi tất cả các phương thức 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ọ trì hoãn thực hiện cho đến khi kết quả thực tế được tính toán (chẳng hạn như với a .Count()hoặc a .ToList()). Vì vậy, khi bạn xâu chuỗi nhiều phương thức với nhau (nhiều lệnh gọi đến .Where(), có thể là một .OrderBy()hoặc một cái gì đó cho hiệu ứng đó, v.v.), chúng sẽ tạo ra cái được gọi là cây biểu thức . 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 đến lúc đánh giá nó.


2
Tôi cảm thấy chết lặng khi không biết mình có thể làm được điều này .. Bạn vừa cứu tôi khỏi quá nhiều mã spaghetti.
ledgeJumper

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

bạn có thể sử dụng điều này với một mệnh đề chọn ở cuối không?

@New_Coder: Tất nhiên. Mệnh đề .Where () không thay đổi kiểu trả về.
David

nó kỳ lạ vì khi tôi làm điều này: List <string> path = db.ClientStatement_Inventory .Where (x => (x.statementYear == yea)) .Where (x => (x.statementMonth == mon)) .Select ( c => c.statementPath) .ToList (); Nó không hoạt động. nhưng nếu tôi chỉ có 1 mệnh đề where thì nó sẽ truy vấn databse của tôi.

24

Bạn có thể tiếp tục xâu 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 một AND.


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

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

Đâ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, đó là giải pháp duy nhất hoạt động cho đến nay. Tôi đã phải thêm mệnh đề 'ở đâu' dựa trên các lựa chọn trong giao diện người dùng.
DJ van Wyk

1
Có cách nào để làm điều này để chỉnh sửa "HOẶC" ở đâu không?
EK_AllDay

11

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

// 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 đủ được đề cập PredicateBuilderlà dưới đây (nhưng bạn cũng có thể kiểm tra trang gốc 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);
  }
}

Lưu ý : Tôi đã thử nghiệm phương pháp này với dự án Thư viện lớp di động và phải sử dụng .Compile()để làm cho nó hoạt động:

Where (vị ngữ .Compile () );


Có lý do tại sao điều này không hoạt động với Entity Framework LINQ?
Ciantic

Đối với tôi cũng hoạt động tốt với EF Core. Vị từ kết quả được dịch chính xác sang SQL.
Thomas Hilbert

5

Chắc chắn:

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

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

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

Hoặc một phép gán lại khác cho results: `results = results.Where ( blah ).


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 mệnh đề where hoặc bạn có thể .Where (). Where (). Where () ... và v.v.


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

Lựa chọn không được chấp nhận vì bạn đang làm việc với một đơn đặt hàng.


0

Chỉ cần sử dụng &&toán tử giống như bạn làm 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)     
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.