Câu hỏi Toán tử LIKE trong LINQ


Có cách nào để so sánh các chuỗi trong một biểu thức C # LINQ tương tự như của SQL LIKE nhà điều hành?

Giả sử tôi có một danh sách chuỗi. Trong danh sách này tôi muốn tìm kiếm một chuỗi. Trong SQL, tôi có thể viết:

SELECT * FROM DischargePort WHERE PortName LIKE '%BALTIMORE%'

Thay vì ở trên, truy vấn muốn có một cú pháp LINQ.

using System.Text.RegularExpressions;
…

var regex = new Regex(sDischargePort, RegexOptions.IgnoreCase);
var sPortCode = Database.DischargePorts
                .Where(p => regex.IsMatch(p.PortName))
                .Single().PortCode;

Cú pháp LINQ trên của tôi không hoạt động. Tôi đã làm gì sai?


76
2018-03-21 06:26


gốc


Truy vấn này chủ yếu làm việc cho tôi khi bạn đặt nó vào vị trí. Nhưng, tôi đang sử dụng trình điều khiển MongoDb Linq và có sự khác biệt thực hiện trong mỗi nhà cung cấp LINQ ... anyway, Cảm ơn. - Mark Ewer


Các câu trả lời:


Thông thường bạn sử dụng String.StartsWith/EndsWith/Contains. Ví dụ:

var portCode = Database.DischargePorts
                       .Where(p => p.PortName.Contains("BALTIMORE"))
                       .Single()
                       .PortCode;

Tôi không biết nếu có một cách để làm biểu thức thông thường thích hợp thông qua LINQ to SQL mặc dù. (Lưu ý rằng nó thực sự phụ thuộc vào nhà cung cấp bạn đang sử dụng - nó sẽ là tốt trong LINQ to Objects; đó là vấn đề liệu nhà cung cấp có thể chuyển đổi cuộc gọi sang định dạng truy vấn gốc của nó, ví dụ: SQL.)

EDIT: Như BitKFu nói, Single nên được sử dụng khi bạn mong đợi chính xác một kết quả - khi đó là lỗi cho điều đó không đúng. Tùy chọn của SingleOrDefault, FirstOrDefault hoặc là First nên được sử dụng tùy thuộc vào chính xác những gì mong đợi.


120
2018-03-21 06:28



bạn nhưng, có một vấn đề, danh sách của tôi chứa "BALTIMORE", và tham số so sánh đã cho của tôi là "BALTIMORE [MD], US". Cú pháp trên không chọn được. - shamim
có một cái nhìn vào tuyên bố của tôi dưới đây, nó có thể đến từ phương thức Single (). Tốt hơn là sử dụng FirstOrDefault () - BitKFu
@shamim: Vì vậy, dữ liệu của bạn không chứa chuỗi bạn đang tìm kiếm? Làm thế nào bạn mong đợi rằng để làm việc ngay cả trong SQL? - Jon Skeet
Trong SQL bạn có thể không nhận được tập kết quả - trong C # bạn sẽ nhận được một ngoại lệ. Đó là hơi khác nhau, thay vì không có kết quả. Đó là lý do tại sao tôi đề nghị sử dụng FirstOrDefault. - BitKFu
@BitKFu từ điểm khởi đầu của Single(), SingleOrDefault()sẽ là bước tiếp theo của tôi, trừ khi chúng ta hiểu bối cảnh đầy đủ ... - Marc Gravell♦


Regex? Không. Nhưng cho truy vấn đó bạn chỉ có thể sử dụng:

 string filter = "BALTIMORE";
 (blah) .Where(row => row.PortName.Contains(filter)) (blah)

nếu bạn có thật không muốn SQL LIKE, bạn có thể dùng System.Data.Linq.SqlClient.SqlMethods.Like(...), bản đồ LINQ-to-SQL nào LIKE trong SQL Server.


28
2018-03-21 06:29



những gì về trong EF4? - Maslow
@ Maslow - không phải là lĩnh vực chuyên môn của tôi, tôi sợ - nhưng tôi không tin rằng có một cách sạch sẽ tốt đẹp để lập bản đồ cho tất cả các triển khai EF, vì vậy ... không. - Marc Gravell♦
điều này có thể hoạt động trên các triển khai SQL nhưng không hoạt động với một bộ sưu tập đối tượng tiêu chuẩn - Chris McGrath


Như Jon Skeet và Marc Gravell đã đề cập, bạn có thể đơn giản lấy một điều kiện chứa. Nhưng trong trường hợp truy vấn giống như bạn, nó rất nguy hiểm để có một câu lệnh đơn (), bởi vì điều đó ngụ ý rằng bạn chỉ tìm thấy 1 kết quả. Trong trường hợp có nhiều kết quả hơn, bạn sẽ nhận được một ngoại lệ tốt đẹp :)

Vì vậy, tôi muốn sử dụng FirstOrDefault () thay vì Single ():

var first = Database.DischargePorts.FirstOrDefault(p => p.PortName.Contains("BALTIMORE"));
var portcode = first != null ? first.PortCode : string.Empty;

8
2018-03-21 06:34



nếu nó là của chúng tôi kỳ vọng khẳng định rằng có chính xác một trận đấu, Single không phải là "nguy hiểm" - đó là "đúng". Tất cả đều đến với những gì chúng tôi đang tuyên bố về dữ liệu ... "bất kỳ số nào", "ít nhất một", "tối đa một", "chính xác một", v.v. - Marc Gravell♦
có, nhưng truy vấn LIKE có thể không phải là một kết quả duy nhất;) - BitKFu
tùy thuộc vào ngữ cảnh, nó có thể ... nó phụ thuộc hoàn toàn vào kỳ vọng của truy vấn - Marc Gravell♦
Điều gì về tìm kiếm "trống" hoặc "%"? Điều này có thể xử lý "B", "BALT" và "" (có nghĩa là có được cho tôi tất cả mọi thứ)? - BlueChippy


Vâng ... đôi khi nó có thể không thoải mái khi sử dụng Contains, StartsWith hoặc là EndsWith đặc biệt khi tìm kiếm giá trị xác định LIKE statment, ví dụ: đã chuyển 'giá trị%' yêu cầu từ nhà phát triển để sử dụng StartsWith chức năng trong biểu thức. Vì vậy, tôi quyết định viết phần mở rộng cho IQueryable các đối tượng.

Sử dụng

// numbers: 11-000-00, 00-111-00, 00-000-11

var data1 = parts.Like(p => p.Number, "%11%");
// result: 11-000-00, 00-111-00, 00-000-11

var data2 = parts.Like(p => p.Number, "11%");
// result: 11-000-00

var data3 = parts.Like(p => p.Number, "%11");
// result: 00-000-11

Mã số

public static class LinqEx
{
    private static readonly MethodInfo ContainsMethod = typeof(string).GetMethod("Contains");
    private static readonly MethodInfo StartsWithMethod = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
    private static readonly MethodInfo EndsWithMethod = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });

    public static Expression<Func<TSource, bool>> LikeExpression<TSource, TMember>(Expression<Func<TSource, TMember>> property, string value)
    {
        var param = Expression.Parameter(typeof(TSource), "t");
        var propertyInfo = GetPropertyInfo(property);
        var member = Expression.Property(param, propertyInfo.Name);

        var startWith = value.StartsWith("%");
        var endsWith = value.EndsWith("%");

        if (startWith)
            value = value.Remove(0, 1);

        if (endsWith)
            value = value.Remove(value.Length - 1, 1);

        var constant = Expression.Constant(value);
        Expression exp;

        if (endsWith && startWith)
        {
            exp = Expression.Call(member, ContainsMethod, constant);
        }
        else if (startWith) 
        {
            exp = Expression.Call(member, EndsWithMethod, constant);
        }
        else if (endsWith)
        {
            exp = Expression.Call(member, StartsWithMethod, constant);
        }
        else
        {
            exp = Expression.Equal(member, constant);
        }

        return Expression.Lambda<Func<TSource, bool>>(exp, param);
    }

    public static IQueryable<TSource> Like<TSource, TMember>(this IQueryable<TSource> source, Expression<Func<TSource, TMember>> parameter, string value)
    {
        return source.Where(LikeExpression(parameter, value));
    }

    private static PropertyInfo GetPropertyInfo(Expression expression)
    {
        var lambda = expression as LambdaExpression;
        if (lambda == null)
            throw new ArgumentNullException("expression");

        MemberExpression memberExpr = null;

        switch (lambda.Body.NodeType)
        {
            case ExpressionType.Convert:
                memberExpr = ((UnaryExpression)lambda.Body).Operand as MemberExpression;
                break;
            case ExpressionType.MemberAccess:
                memberExpr = lambda.Body as MemberExpression;
                break;
        }

        if (memberExpr == null)
            throw new InvalidOperationException("Specified expression is invalid. Unable to determine property info from expression.");


        var output = memberExpr.Member as PropertyInfo;

        if (output == null)
            throw new InvalidOperationException("Specified expression is invalid. Unable to determine property info from expression.");

        return output;
    }
}

7
2018-02-25 19:07



Bạn có phiên bản hoạt động với IEnumerable? - Nicke Manarin


Trong LINQ bản địa, bạn có thể sử dụng sự kết hợp của Contains/StartsWith/EndsWith hoặc RegExp.

Trong phương thức sử dụng LINQ2SQL SqlMethods.Like()

    from i in db.myTable
    where SqlMethods.Like(i.field, "tra%ata")
    select i

thêm Assembly: System.Data.Linq (trong System.Data.Linq.dll) để sử dụng tính năng này.


6
2018-04-06 15:10





Đơn giản như thế này

string[] users = new string[] {"Paul","Steve","Annick","Yannick"};    
var result = from u in users where u.Contains("nn") select u;

Quả tìm kiếm -> Annick, Yannick


3
2018-01-01 19:14





Bạn có thể gọi phương thức đơn với một biến vị ngữ:

var portCode = Database.DischargePorts
                   .Single(p => p.PortName.Contains("BALTIMORE"))
                   .PortCode;

2
2018-03-21 06:32





  .Where(e => e.Value.StartsWith("BALTIMORE"))

Điều này hoạt động giống như "LIKE" của SQL ...


2
2017-12-26 20:58



không .. không có nó không chỉ hoạt động giống như 'thuật ngữ' tương tự '', nó không còn hoạt động giống như toán tử giống như một tổng thể và không hỗ trợ các ký tự đại diện - Chris McGrath