Pertanyaan LIKE operator di LINQ


Apakah ada cara untuk membandingkan string dalam ekspresi C # LINQ mirip dengan SQL LIKE operator?

Misalkan saya memiliki daftar string. Pada daftar ini saya ingin mencari string. Di SQL, saya bisa menulis:

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

Alih-alih di atas, permintaan ingin sintaks linq.

using System.Text.RegularExpressions;
…

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

Sintaks LINQ saya di atas tidak berfungsi. Apa yang saya salah?


76
2018-03-21 06:26


asal


Jawaban:


Biasanya Anda gunakan String.StartsWith/EndsWith/Contains. Sebagai contoh:

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

Saya tidak tahu apakah ada cara melakukan ekspresi reguler yang tepat melalui LINQ to SQL sekalipun. (Perhatikan bahwa itu benar-benar tergantung pada penyedia yang Anda gunakan - itu akan baik-baik saja di LINQ to Objects; ini masalah apakah penyedia dapat mengonversi panggilan ke format kueri aslinya, misalnya SQL.)

EDIT: Seperti BitKFu mengatakan, Single harus digunakan ketika Anda harapkan tepat satu hasil - ketika itu kesalahan untuk itu tidak menjadi kasus. Pilihan dari SingleOrDefault, FirstOrDefault atau First harus digunakan tergantung pada persis apa yang diharapkan.


120
2018-03-21 06:28



Regex? tidak. Tapi untuk permintaan itu Anda bisa menggunakan:

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

Jika kamu sangat ingin SQL LIKE, Kamu dapat memakai System.Data.Linq.SqlClient.SqlMethods.Like(...), yang LINQ-to-SQL maps ke LIKE di SQL Server.


28
2018-03-21 06:29



Seperti yang telah disebutkan oleh Jon Skeet dan Marc Gravell, Anda dapat dengan mudah mengambil kondisi berisi. Tetapi dalam kasus permintaan serupa Anda, sangat berbahaya untuk mengambil pernyataan Single (), karena itu menyiratkan bahwa Anda hanya menemukan 1 hasil. Dalam kasus hasil lebih banyak, Anda akan menerima pengecualian bagus :)

Jadi saya lebih suka menggunakan FirstOrDefault () daripada 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



Yah ... kadang-kadang mungkin tidak nyaman digunakan Contains, StartsWith atau EndsWith terutama ketika mencari nilai menentukan LIKE statment mis. melewati 'nilai%' membutuhkan dari pengembang untuk digunakan StartsWith berfungsi dalam ekspresi. Jadi saya memutuskan untuk menulis ekstensi untuk IQueryable objek.

Pemakaian

// 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

Kode

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



Dalam LINQ asli Anda dapat menggunakan kombinasi Contains/StartsWith/EndsWith atau RegExp.

Dalam metode penggunaan LINQ2SQL SqlMethods.Like()

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

tambahkan Assembly: System.Data.Linq (dalam System.Data.Linq.dll) untuk menggunakan fitur ini.


6
2018-04-06 15:10



Sederhana seperti ini

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

Hasil -> Annick, Yannick


3
2018-01-01 19:14



Anda dapat memanggil metode tunggal dengan predikat:

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

2
2018-03-21 06:32



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

Ini berfungsi seperti "LIKE" dari SQL ...


2
2017-12-26 20:58