Linq: thêm điều kiện vào mệnh đề where một cách có điều kiện


103

Tôi có một truy vấn như thế này

(from u in DataContext.Users
       where u.Division == strUserDiv 
       && u.Age > 18
       && u.Height > strHeightinFeet  
       select new DTO_UserMaster
       {
         Prop1 = u.Name,
       }).ToList();

Tôi muốn thêm các điều kiện khác nhau như tuổi, chiều cao dựa trên việc các điều kiện đó có được cung cấp cho phương thức chạy truy vấn này hay không. Tất cả các điều kiện sẽ bao gồm Phân chia người dùng. Nếu tuổi được cung cấp, tôi muốn thêm tuổi đó vào truy vấn. Tương tự, nếu chiều cao được cung cấp, tôi cũng muốn thêm chiều cao đó.

Nếu điều này được thực hiện bằng cách sử dụng truy vấn sql, tôi đã sử dụng trình tạo chuỗi để nối chúng vào truy vấn strSQL chính. Nhưng ở đây trong Linq, tôi chỉ có thể nghĩ đến việc sử dụng điều kiện IF, nơi tôi sẽ viết ba lần truy vấn giống nhau, với mỗi khối IF có một điều kiện bổ sung. Có cách nào tốt hơn để làm điều này?

Câu trả lời:


182

Nếu bạn không gọi ToList()và ánh xạ cuối cùng của bạn với loại DTO, bạn có thể thêm Wherecác mệnh đề khi bạn tiếp tục và xây dựng kết quả ở cuối:

var query = from u in DataContext.Users
   where u.Division == strUserDiv 
   && u.Age > 18
   && u.Height > strHeightinFeet
   select u;

if (useAge)
   query = query.Where(u => u.Age > age);

if (useHeight)
   query = query.Where(u => u.Height > strHeightinFeet);

// Build the results at the end
var results = query.Select(u => new DTO_UserMaster
   {
     Prop1 = u.Name,
   }).ToList();

Điều này sẽ vẫn chỉ dẫn đến một lệnh gọi đến cơ sở dữ liệu, điều này sẽ hiệu quả tương tự như việc viết truy vấn trong một lần chuyển.


1
Tôi có cần đặt tất cả các điều kiện where trong câu lệnh "var query = .." không?
user20358

4
Các điều kiện tiếp theo Trường hợp các điều kiện được tổng hợp dưới dạng OR hoặc AND?
Vi100

4
@ vi100 chúng sẽ là các bộ lọc bổ sung, vì vậy VÀ
Reed Copsey

Cảm ơn chúa vì sự đơn giản! Tôi phát ngán khi nhìn thấy hơn 20 truy vấn Linq dòng trong khi phần trên dễ đọc hơn nhiều
justa

Tại sao tôi gặp lỗi nàyLINQ to Entities does not recognize the method 'System.String get_Item(System.String)' method, and this method cannot be translated into a store expression.
Ali Umair

19

Tôi thường sử dụng phương pháp chuỗi nhưng có cùng một vấn đề. Và đây là tiện ích mở rộng tôi sử dụng

public static IQueryable<T> ConditionalWhere<T>(
        this IQueryable<T> source, 
        Func<bool> condition,
        Expression<Func<T, bool>> predicate)
    {
        if (condition())
        {
            return source.Where(predicate);
        }

        return source;
    }

Nó giúp tránh đứt dây chuyền. Cũng giống nhau ConditionalOrderByConditionalOrderByDescendingđều hữu ích.


Hữu ích, nhưng bạn có vui lòng thêm một ví dụ về nó trông như thế nào khi sử dụng.
Suncat2000

1
Nó sẽ giống như: var fruit = await db.Fruits .ConditionalWhere (() => color! = Null, f => f.Color == color) .ConditionalWhere (() => nine! = Null, f => f .Ripe == chin) .ToListAsync ();
Yuriy Granovskiy

4
Hoạt động tuyệt vời! Cảm ơn! Tôi cũng tạo quá tải cho điều kiện dưới dạng giá trị boolean đơn giản thay vì một hàm, để làm cho nó trực quan hơn trong đó một đại biểu sẽ thêm độ phức tạp không cần thiết. Tôi sử dụng phương pháp mở rộng này khá thường xuyên và đánh giá cao giải pháp của bạn rất nhiều.
Suncat2000

17

một lựa chọn.

bool? age = null

(from u in DataContext.Users
           where u.Division == strUserDiv 
           && (age == null || (age != null && u.Age > age.Value))
           && u.Height > strHeightinFeet  
           select new DTO_UserMaster
           {
             Prop1 = u.Name,
           }).ToList();

hoặc bạn có thể chuyển sang cú pháp phương thức cho linq và sử dụng điều kiện if để đính kèm các biểu thức vào mệnh đề where.


3

Đơn giản là tôi đang sử dụng nó trong mệnh đề where của tôi như

    public IList<ent_para> getList(ent_para para){
     db.table1.Where(w=>(para.abc!=""?w.para==para.abc:true==true) && (para.xyz!=""?w.xyz==para.xyz:true==true)).ToList();
}

3

Dựa trên điều kiện nhất định, thêm điều kiện where ...

from u in DataContext.Users
where u.Division == strUserDiv 
&& u.Age != null ? u.Age > 18 : 1== 1
&& u.Height != null ? u.Height > 18 : 1== 1
&& u.Height != null ? u.Height > 18 : 1== 1
 select new DTO_UserMaster
       {
         Prop1 = u.Name,
       }).ToList();

2

Đây là mã của tôi để làm một điều tương tự. Đây là một phương thức trên api WCF SOAP Web Service của tôi.

    public FruitListResponse GetFruits(string color, bool? ripe)
    {
        try
        {
            FruitContext db = new FruitContext();
            var query = db.Fruits.Select(f => f);
            if (color != null)
            {
                query = query.Where(f => f.Color == color);
            }
            if (ripe != null)
            {
                query = query.Where(f => f.Ripe == ripe);
            }
            return new FruitListResponse
            {
                Result = query.Select(f => new Fruit { Id = f.FruitId, Name = f.Name }).ToList()
            };
        }
        catch (Exception e)
        {
            return new FruitListResponse { ErrorMessage = e.Message };
        }
    }

Truy vấn Select(f => f)cơ bản có nghĩa là về cơ bản MỌI THỨ, và các Wheremệnh đề được tùy chọn đính kèm với nó. Cuối cùng Selectlà tùy chọn. Tôi sử dụng để chuyển đổi các đối tượng hàng trong cơ sở dữ liệu thành các đối tượng kết quả "Fruit".


0

Giả sử tham số sau,

Int? Age = 18;

Chỉ cần sử dụng các toán tử có điều kiện &&||chúng ta có thể có một phiên bản khác.

(from u in DataContext.Users
where u.Division == strUserDiv 
    && (Age == null || u.Age > Age)
    && (Param1 == null || u.param1 == Param1)
    && u.Height > strHeightinFeet
select new DTO_UserMaster
{
    Prop1 = u.Name,
}).ToList();

Giống như Param1, bạn có thể thêm bất kỳ số lượng tham số nào cho điều kiện tìm kiếm.


0

Tôi vừa bắt gặp điều này để tìm kiếm thứ gì đó khác, nhưng nghĩ rằng tôi sẽ ném vào phiên bản lambda.

Đầu tiên, tôi sẽ tạo một lớp như thế này để chuyển các tham số vào một lớp dữ liệu:

   public class SearchParameters() {
       public int? Age {get; set;}
       public string Division {get;set;}
       etc
    }

Sau đó, trong lớp dữ liệu của tôi, giống như sau:

public IQueryable<User> SearchUsers(SearchParameters params) 
{
    var query = Context.Users;
    if (params.Age.HasValue)
    {
         query = query.Where(u => u.Age == params.Age.Value);
    }
    if (!string.IsNullOrEmpty(params.Division)
    {
        query = query.Where(u => u.Division == params.Division);
    }
    etc
    return query;
}

Nơi bạn thực hiện truy vấn là tùy thuộc vào bạn. Có thể có một lớp giữa ứng dụng và dữ liệu chuyển đổi các đại diện dành riêng cho db thành db-bất khả tri (có thể bạn truy vấn nhiều nguồn dữ liệu). Ví dụ, lớp đó có thể nhận được nhiều loại truy vấn từ các nguồn này và ánh xạ chúng đến một biểu diễn POCO chung.


Rất tiếc, tôi không thấy câu trả lời của John Henckel. Ý tưởng tương tự.
Scott Peterson

0

Chỉ để thêm vào câu trả lời được chấp nhận ở trên ở đây , nếu bạn đang thực hiện tìm kiếm động trên một phép nối, hãy xem xét trả về một đối tượng mới với cả hai bảng (t1, t2) trong truy vấn linq ban đầu để bạn có thể truy cập chúng riêng lẻ để thực hiện điều kiện Tìm kiếm.

var query = from t1 in _context.Table1
            join t2 in _context.Table2 on t1.Table1Id equals t2.Table1IdId
            select new { t1, t2 };

        if (!string.IsNullOrEmpty(searchProperty1))
        {
            query = query.Where(collection => collection.t1.TableColumn == searchProperty1);
        }
        if (!string.IsNullOrEmpty(searchProperty2))
        {
            query = query.Where(collection => collection.t2.TableColumn == searchProperty2);
        }
        ....etc.

Tôi đã nhận được câu trả lời mà tôi đang tìm kiếm ở đây liên quan đến việc kết hợp hai bảng và truy vấn các cột cụ thể trên một trong hai bảng

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.