2009-03-30 88 views
5

Giả sử tôi có một mảng, và tôi muốn thực hiện truy vấn LINQ đối với một varchar trả về bất kỳ bản ghi nào có phần tử của mảng ở bất kỳ đâu trong varchar.LINQ cho truy vấn LIKE của các phần tử mảng

Thứ gì đó như thế này sẽ ngọt ngào.

string[] industries = { "airline", "railroad" }

var query = from c in contacts where c.industry.LikeAnyElement(industries) select c

Bất kỳ ý tưởng nào?

+0

LINQ to SQL, LINQ to Entities, LINQ to Objects? – Lucas

Trả lời

5

Đây thực sự là một ví dụ tôi sử dụng trong tôi "Express Yourself" trình bày, kiếm cái gì đó là khó có thể làm trong LINQ thường xuyên; Theo như tôi biết, cách dễ nhất để làm điều này là bằng cách viết vị từ theo cách thủ công. Tôi sử dụng ví dụ dưới đây (lưu ý nó sẽ làm việc như nhau cho StartsWith vv):

using (var ctx = new NorthwindDataContext()) 
    { 
     ctx.Log = Console.Out; 
     var data = ctx.Customers.WhereTrueForAny(
      s => cust => cust.CompanyName.Contains(s), 
      "a", "de", "s").ToArray(); 
    } 
// ... 
public static class QueryableExt 
{ 
    public static IQueryable<TSource> WhereTrueForAny<TSource, TValue>(
     this IQueryable<TSource> source, 
     Func<TValue, Expression<Func<TSource, bool>>> selector, 
     params TValue[] values) 
    { 
     return source.Where(BuildTrueForAny(selector, values)); 
    } 
    public static Expression<Func<TSource, bool>> BuildTrueForAny<TSource, TValue>(
     Func<TValue, Expression<Func<TSource, bool>>> selector, 
     params TValue[] values) 
    { 
     if (selector == null) throw new ArgumentNullException("selector"); 
     if (values == null) throw new ArgumentNullException("values"); 
     if (values.Length == 0) return x => true; 
     if (values.Length == 1) return selector(values[0]); 

     var param = Expression.Parameter(typeof(TSource), "x"); 
     Expression body = Expression.Invoke(selector(values[0]), param); 
     for (int i = 1; i < values.Length; i++) 
     { 
      body = Expression.OrElse(body, 
       Expression.Invoke(selector(values[i]), param)); 
     } 
     return Expression.Lambda<Func<TSource, bool>>(body, param); 
    } 

} 
+0

Tốt! ít nhất 10 ký tự.) – Lucas

4
from c in contracts 
where industries.Any(i => i == c.industry) 
select c; 

điều gì đó tương tự. sử dụng bất kỳ phương pháp nào trên bộ sưu tập.

+1

Điều này ném một ngoại lệ trong LINQ to SQL. Nó có thể được viết là "where industries.Contains (c.industry)", được dịch là "c.industry IN (" airlines "," railroad ")", nhưng anh ấy muốn so sánh LIKE. – Lucas

0

Thật không may, LIKE không được hỗ trợ trong LINQ to SQL theo đây:

http://msdn.microsoft.com/en-us/library/bb882677.aspx

Để làm được việc này, bạn sẽ phải viết một stored procedure mà sẽ chấp nhận các thông số bạn muốn sử dụng trong các câu lệnh tương tự và sau đó gọi từ LINQ to SQL.


Cần lưu ý rằng một số câu trả lời được đề xuất sử dụng Chứa. Điều này sẽ không hoạt động vì có vẻ như toàn bộ chuỗi khớp với phần tử mảng. Những gì đang được xem xét là cho các phần tử mảng được chứa trong lĩnh vực riêng của mình, một cái gì đó như:

industry LIKE '%<element>%' 

Như Clark đã đề cập trong một chú thích, bạn có thể sử dụng một cuộc gọi đến IndexOf trên mỗi phần tử (mà nên dịch cho một cuộc gọi SQL):

string[] industries = { "airline", "railroad" } 

var query = 
    from c in contacts 
    where 
     c.industry.IndexOf(industries[0]) != -1 || 
     c.industry.IndexOf(industries[1]) != -1 

Nếu bạn biết độ dài của mảng và số phần tử, thì bạn có thể mã hóa mã này. Nếu không, bạn sẽ phải tạo cá thể Expression dựa trên mảng và trường bạn đang xem.

+0

Tôi biết rằng .. xấu của tôi .. một charindex! = -1 cho mỗi mục trong mảng sẽ làm tốt. – Clark

+1

thực sự LIKE được hỗ trợ một phần trong LINQ to SQL. "nơi c.industry.Contains (" hãng hàng không ")" hoạt động và dịch thành "WHERE c.industry LIKE"% hãng hàng không% '. Nhưng anh ấy muốn NHƯNG bất kỳ giá trị đã cho nào, không chỉ một giá trị đã cho, không chỉ là một giá trị. – Lucas

3

IEnumerable.Contains() dịch để SQL TRÊN như trong:

WHERE 'american airlines' IN ('airline', 'railroad') -- FALSE 

String.Contains() mà dịch để SQL NHƯ% ...% như trong:

WHERE 'american airlines' LIKE '%airline%' -- TRUE 

Nếu bạn muốn địa chỉ liên lạc ở đâu ngành công nghiệp của liên hệ là LIKE (chứa) bất kỳ ngành nào đã cho, bạn muốn kết hợp cả Any() và String.Contains() vào một cái gì đó như thế này:

string[] industries = { "airline", "railroad" }; 

var query = from c in contacts 
      where industries.Any(i => c.Industry.Contains(i)) 
      select c; 

Tuy nhiên, kết hợp cả hai Any() và String.Contains() như thế này là KHÔNG hỗ trợ trong LINQ to SQL. Nếu các thiết lập của ngành công nghiệp nhất định là nhỏ, bạn có thể thử một cái gì đó như:

where c.Industry.Contains("airline") || 
     c.Industry.Contains("railroad") || ... 

Hoặc (mặc dù thường không khuyến khích) nếu tập các địa chỉ liên lạc là đủ nhỏ, bạn có thể mang lại cho họ tất cả từ DB và áp dụng bộ lọc với LINQ to Objects bằng cách sử dụng contacts.AsEnumerable() hoặc contacts.ToList() như là nguồn gốc của các truy vấn trên:

var query = from c in contacts.AsEnumerable() 
      where industries.Any(i => c.Industry.Contains(i)) 
      select c; 
1

nó sẽ làm việc nếu bạn xây dựng các truy vấn như sau:

var query = từ c trong contacts.AsEnumerable() chọn c;

truy vấn = truy vấn.Where (c => (c.Industry.Contains ("airline")) || (c.Industry.Contains ("railroad")));

bạn chỉ cần tạo chuỗi theo cách lập trình ở trên nếu thông số hãng hàng không và đường sắt là đầu vào của người dùng. Điều này thực ra phức tạp hơn một chút so với tôi mong đợi. Xem bài viết - http://www.albahari.com/nutshell/predicatebuilder.aspx

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