2009-08-04 33 views
6

Tôi cố gắng để làm một so sánh như dựa trên một thông số bên ngoài (thông qua một hình thức tìm kiếm) xác định loại so sánh ("%string" hoặc "string%" hoặc "%string%")LINQ, Expressions, NHibernate và Giống như so sánh

Tôi đã suy nghĩ theo hướng sau:

query = query.Where(
    Entity.StringProperty.Like("SearchString", SelectedComparsionType) 
) 

Giống như phương pháp sẽ hơn dựa trên loại được lựa chọn trở lại .StartsWith() hoặc .EndsWith() hoặc .SubString()

Kiến thức của tôi về các biểu thức rõ ràng là rất lớn, vì tôi không thể xây dựng một phương thức có thể mang lại kết quả đúng (so sánh phía máy chủ trong SQL giống như phương thức StartsWith).

Trả lời

17

Cách dễ dàng

Chỉ cần sử dụng

if (comparison == ComparisonType.StartsWith) 
    query = query.Where(e => e.StringProperty.StartsWith("SearchString")); 
else if ... 

Cách cứng

Nếu bạn muốn làm một cái gì đó như thế này, hoặc là đảm bảo cung cấp LINQ của bạn có thể được thông báo của phương pháp mới này bằng cách nào đó, và làm thế nào nó dịch sang SQL (không), hoặc ngăn chặn phương pháp của bạn từ bao giờ đạt đến nhà cung cấp LINQ, và cung cấp cho nhà cung cấp một cái gì đó nó hiểu (ha rd). Ví dụ, thay vì

query.Where(e => CompMethod(e.StringProperty, "SearchString", comparsionType)) 

bạn có thể tạo một cái gì đó giống như

var query = source.WhereLike(e => e.StringProperty, "SearchString", comparsionType) 

với đoạn mã sau

public enum ComparisonType { StartsWith, EndsWith, Contains } 

public static class QueryableExtensions 
{ 
    public static IQueryable<T> WhereLike<T>(
     this IQueryable<T> source, 
     Expression<Func<T, string>> field, 
     string value, 
     SelectedComparisonType comparisonType) 
    { 
     ParameterExpression p = field.Parameters[0]; 
     return source.Where(
      Expression.Lambda<Func<T, bool>>(
       Expression.Call(
        field.Body, 
        comparisonType.ToString(), 
        null, 
        Expression.Constant(value)), 
      p)); 
    } 
} 

Bạn thậm chí có thể thêm tiêu chí bổ sung theo cách này

var query = from e in source.WhereLike(
       e => e.StringProperty, "SearchString", comparsionType) 
      where e.OtherProperty == 123 
      orderby e.StringProperty 
      select e; 

Cách rất, rất khó khăn

Nó sẽ (kỹ thuật) có thể viết lại cây biểu trước các nhà cung cấp nhìn thấy nó, vì vậy bạn thể sử dụng truy vấn mà bạn đã có trong tâm trí ở nơi đầu tiên, nhưng bạn' d phải

  • tạo Where(this IQueryable<EntityType> source, Expression<Func<EntityType, bool>> predicate) để đánh chặn các Queryable.Where,
  • viết lại cây biểu thức, thay thế CompMethod của bạn, bất cứ nơi nào nó là, với một trong những phương pháp String,
  • gọi số Queryable.Where gốc với biểu thức viết lại,
  • và trước hết, có thể thực hiện theo phương pháp tiện ích mở rộng ở trên ngay từ đầu!

Nhưng đó có thể là cách quá phức tạp đối với những gì bạn nghĩ.

+0

Ruben: Hiện tượng, đó là một địa ngục của một lời giải thích - đầy đủ, dễ hiểu, kỹ lưỡng và chính xác những gì tôi đang tìm kiếm, cảm ơn bạn. Tôi cũng muốn cảm ơn người khác vì sự giúp đỡ của họ. –

-1

Bạn nên sử dụng Regex để giải quyết vấn đề này.

+0

Điều này sẽ không dẫn đến một nhà điều hành LIKE cơ sở dữ liệu, mà tôi nghĩ rằng OP mong muốn – MattH

1

Âm thanh như bạn nên muốn sử dụng:

query = query.Where(
Entity.StringProperty.Contains("SearchString") 
) 

này nên bản đồ để:

WHERE StringProperty LIKE '%SearchString%' 

này cũng nên làm việc cho mặt nạ tìm kiếm nâng cao hơn như "Ông Sm% th?" , nhưng tôi chưa phải thử nghiệm bất kỳ chuỗi tìm kiếm nào giống như vậy.


UPDATE: Dựa trên Ops chỉnh sửa

Nghe có vẻ giống như những gì bạn đang yêu cầu là một cái gì đó như sau:

public enum SelectedComparsionType 
    { 
     StartsWith, 
     EndsWith, 
     Contains 
    } 

public static bool Like(this string searchString, string searchPattern, SelectedComparsionType searchType) 
{ 
    switch (searchType) 
    { 
     case SelectedComparsionType.StartsWith: 
      return searchString.StartsWith(searchPattern); 
     case SelectedComparsionType.EndsWith: 
      return searchString.EndsWith(searchPattern); 
     case SelectedComparsionType.Contains: 
     default: 
      return searchString.Contains(searchPattern); 
    } 
} 

này sẽ cho phép bạn viết mã như bạn yêu cầu , ví dụ:

query = query.Where(
Entity.StringProperty.Like("SearchString", SelectedComparsionType.StartsWith) 
) 

Tuy nhiên, cá nhân, tôi sẽ thay thế bất kỳ việc sử dụng SelectedComparsionType nào, với lệnh gọi trực tiếp đến hàm chuỗi được yêu cầu. I.e

query = query.Where(
Entity.StringProperty.StartsWith("SearchString") 
) 

Vì điều này vẫn sẽ ánh xạ tới truy vấn 'LIKE' của SQL.

0

Đây chính xác là những gì tôi có trong đầu, cảm ơn bạn. Tôi đã có một cái gì đó tương tự đã được viết, nhưng nó không dịch sang SQL. Ví dụ, nó làm việc nếu tôi đã làm điều này trực tiếp:

Entity.StringProperty.EndsWith("SearchString"); 

Nó không làm việc nếu tôi sử dụng một phương pháp chuyên dụng:

CompMethod("BaseString","SearchString",SelectedComparsionType.EndsWith) 

Tôi nghĩ rằng nó có thể có một cái gì đó để làm với đánh giá biểu hiện, i chỉ là không chắc chắn những gì.

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