Linq to SQL cách thực hiện “ở đâu [cột] trong (danh sách các giá trị)”


101

Tôi có một chức năng trong đó tôi lấy danh sách id và tôi cần trả lại danh sách khớp với mô tả được liên kết với id. Ví dụ:

public class CodeData
{
    string CodeId {get; set;}
    string Description {get; set;}
}

public List<CodeData> GetCodeDescriptionList(List<string> codeIDs)
    //Given the list of institution codes, return a list of CodeData
    //having the given CodeIds
}

Vì vậy, nếu tôi đang tự tạo sql cho điều này, tôi chỉ cần làm điều gì đó như sau (trong đó mệnh đề in chứa tất cả các giá trị trong đối số codeIds):

Select CodeId, Description FROM CodeTable WHERE CodeId IN ('1a','2b','3')

Trong Linq to Sql, tôi dường như không thể tìm thấy mệnh đề tương đương với mệnh đề "IN". Điều tốt nhất tôi tìm thấy cho đến nay (không hoạt động) là:

 var foo = from codeData in channel.AsQueryable<CodeData>()
           where codeData.CodeId == "1" || codeData.CodeId == "2"
           select codeData;

Vấn đề là tôi không thể tạo động danh sách các mệnh đề "HOẶC" cho linq thành sql, vì chúng được đặt tại thời điểm biên dịch.

Làm cách nào để thực hiện mệnh đề where kiểm tra một cột nằm trong danh sách giá trị động bằng cách sử dụng Linq to Sql?

Câu trả lời:


159

Sử dụng

where list.Contains(item.Property)

Hoặc trong trường hợp của bạn:

var foo = from codeData in channel.AsQueryable<CodeData>()
          where codeIDs.Contains(codeData.CodeId)
          select codeData;

Nhưng bạn cũng có thể làm điều đó trong ký hiệu dấu chấm:

var foo = channel.AsQueryable<CodeData>()
                 .Where(codeData => codeIDs.Contains(codeData.CodeId));

làm thế nào để sử dụng trong trường hợp CodeId là Số nguyên ??
Kiran Solkar

2
@KiranSolkar: Sau đó, có lẽ codeIDssẽ là một List<int>, và tất cả sẽ ổn.
Jon Skeet

@JonSkeet Đó không phải là trường hợp nhạy cảm sao? Nếu codeID là danh sách các chuỗi chữ hoa và codeData.codeId là một chuỗi chữ thường, nó sẽ không thành công.
PersyJack

@PersyJack: Không có gì thắc mắc về việc nó phải phân biệt chữ hoa chữ thường. Về việc có hay không, tôi không thể nhớ liệu LINQ to SQL có thực thi phân biệt chữ hoa chữ thường theo mặc định hay để cài đặt db chi phối nó.
Jon Skeet,

1
@PersyJack LINQ to SQL tạo truy vấn T-SQL, sau đó chạy trên SQL Server bằng cách sử dụng cài đặt cơ sở dữ liệu cho phân biệt chữ hoa chữ thường. Mặc dù, nếu một người không cẩn thận và hiện thực hóa kết quả truy vấn, trước khi áp dụng LINQ cho các đối tượng trong bộ nhớ, chúng có thể phải chịu hậu quả của việc phân biệt chữ hoa chữ thường không khớp.
Zarepheth

26

Bạn cũng có thể sử dụng:

List<int> codes = new List<int>();

codes.add(1);
codes.add(2);

var foo = from codeData in channel.AsQueryable<CodeData>()
          where codes.Any(code => codeData.CodeID.Equals(code))
          select codeData;

1
Tôi đã sử dụng điều này kể từ khi triển khai thực hiện của chúng ta về IQToolkit không hỗ trợ Chứa ()
DJ van Wyk

1

Tôi đã sử dụng phương pháp trong câu trả lời của Jon Skeet, nhưng một phương pháp khác xảy ra với tôi khi sử dụng Concat. Các Concatphương pháp thực hiện tốt hơn một chút trong một thử nghiệm hạn chế, nhưng đó là một rắc rối và tôi sẽ có lẽ chỉ gắn bó với Contains, hoặc có lẽ tôi sẽ viết một phương pháp helper để làm điều này cho tôi. Dù bằng cách nào, đây là một tùy chọn khác nếu bất kỳ ai quan tâm:

Phương pháp

// Given an array of id's
var ids = new Guid[] { ... };

// and a DataContext
var dc = new MyDataContext();

// start the queryable
var query = (
    from thing in dc.Things
    where thing.Id == ids[ 0 ]
    select thing 
);

// then, for each other id
for( var i = 1; i < ids.Count(); i++ ) {
    // select that thing and concat to queryable
    query.Concat(
        from thing in dc.Things
        where thing.Id == ids[ i ]
        select thing
    );
}

Kiểm tra hiệu suất

Điều này không phải là khoa học từ xa. Tôi tưởng tượng cấu trúc cơ sở dữ liệu của bạn và số lượng ID liên quan đến danh sách sẽ có tác động đáng kể.

Tôi đã thiết lập một thử nghiệm trong đó tôi đã thực hiện 100 lần thử nghiệm ConcatContainsmỗi lần thử nghiệm bao gồm việc chọn 25 hàng được chỉ định bởi danh sách ngẫu nhiên các khóa chính. Tôi đã chạy điều này khoảng chục lần, và hầu hết các lần Concatphương pháp chạy nhanh hơn 5 - 10%, mặc dù một lần Containsphương pháp này đã thắng chỉ bằng một smidgen.


0
 var filterTransNos = (from so in db.SalesOrderDetails
                    where  ItemDescription.Contains(ItemDescription)
                            select new { so.TransNo }).AsEnumerable();    


listreceipt = listreceipt.Where(p => filterTransNos.Any(p2 => p2.TransNo == p.TransNo)).ToList();

-1

Đây là cách tôi làm điều đó bằng cách sử dụng HashSet

        HashSet<String> hs = new HashSet<string>(new String[] { "Pluto", "Earth", "Neptune" });
        String[] arr =
        {
            "Pluto",
            "Earth",
            "Neptune",
            "Jupiter",
            "Saturn",
            "Mercury",
            "Pluto",
            "Earth",
            "Neptune",
            "Jupiter",
            "Saturn",
            "Mercury",
            // etc.
        };
        ICollection<String> coll = arr;

        String[] arrStrFiltered = coll.Where(str => hs.Contains(str)).ToArray();

HashSet về cơ bản gần như là O (1) nên độ phức tạp của bạn vẫn là O (n).


Đây là về LINQ-to-SQL. Không áp dụng các cân nhắc LINQ-to-object như vậy.
Gert Arnold

ICollection cũng có thể đến từ LINQ-SQL, đây là một cách chung chung
MG

Câu hỏi là về cách xây dựng một biểu thức có thể chuyển thành SQL chính xác. Điều đó không liên quan gì đến cách tìm kiếm bộ sưu tập cục bộ. Câu trả lời của bạn sẽ chỉ làm mất lòng những độc giả tương lai không biết về sự khác biệt này.
Gert Arnold
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.