LINQ中的LIKE运算符

时间:2011-03-21 06:26:49

标签: c# linq sql-like

有没有办法比较C#LINQ表达式中类似于SQL的LIKE运算符的字符串?

假设我有一个字符串列表。在此列表中,我想搜索一个字符串。在SQL中,我可以写:

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

而不是上述内容,查询需要linq语法。

using System.Text.RegularExpressions;
…

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

我上面的LINQ语法不起作用。我有什么问题?

17 个答案:

答案 0 :(得分:125)

通常您使用String.StartsWith / EndsWith / Contains。例如:

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

我不知道是否有办法通过LINQ to SQL做正确的正则表达式。 (请注意,它确实取决于您正在使用的提供程序 - 它在LINQ to Objects中会很好;这是提供程序是否可以将调用转换为其本机查询格式,例如SQL。)

编辑:正如BitKFu所说,当您期望恰好一个结果时,应该使用Single - 当它出现错误时就不会出现这种情况。应使用SingleOrDefaultFirstOrDefaultFirst的选项,具体取决于完全预期的内容。

答案 1 :(得分:30)

正则表达式?没有。但对于该查询你可以使用:

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

如果您 确实 想要SQL LIKE,您可以使用System.Data.Linq.SqlClient.SqlMethods.Like(...),LINQ-to-SQL映射到LIKE在SQL Server中。

答案 2 :(得分:10)

嗯......有时使用ContainsStartsWithEndsWith可能会感到不舒服,尤其是在搜索值确定LIKE个参数时,例如传递'value%'要求开发人员在表达式中使用StartsWith函数。所以我决定为IQueryable个对象编写扩展名。

用法

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

代码

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;
    }
}

答案 3 :(得分:8)

正如Jon Skeet和Marc Gravell已经提到的,你可以简单地采取一个包含条件。但是在你喜欢查询的情况下,采用Single()语句是非常危险的,因为这意味着你只能找到1个结果。如果有更多结果,您将收到一个很好的例外:)

所以我更喜欢使用FirstOrDefault()而不是Single():

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

答案 4 :(得分:7)

在原生LINQ中,您可以使用Contains/StartsWith/EndsWith或RegExp。

的组合

在LINQ2SQL中使用方法SqlMethods.Like()

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

添加程序集:System.Data.Linq(在System.Data.Linq.dll中)以使用此功能。

答案 5 :(得分:3)

这很简单

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

结果 - &gt;安妮克,雅尼克

答案 6 :(得分:2)

您可以使用谓词调用单个方法:

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

答案 7 :(得分:2)

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

这就像SQL的“LIKE”......

答案 8 :(得分:2)

理想情况下,您应该使用StartWithEndWith

以下是一个例子:

DataContext  dc = new DCGeneral();
List<Person> lstPerson= dc.GetTable<Person>().StartWith(c=> c.strNombre).ToList();

return lstPerson;

答案 9 :(得分:0)

Great custom LIKE function by @adobrzyc<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vlastna responzivna stranka</title> <link rel="stylesheet" href="css/styles2.css"> <link rel="preconnect" href="https://fonts.gstatic.com"> <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@100;400&display=swap" rel="stylesheet"> <link rel="preconnect" href="https://fonts.gstatic.com"> <link href="https://fonts.googleapis.com/css2?family=Cinzel&display=swap" rel="stylesheet"> </head> <body> <div class="container"> <h1 class="nadpis">Take zaujimave veci, ktore sa daju spravit s JS a JQuery</h1> <h2 class="podnadpis">Image Slider</h2> <div class="slider-outer"> <img src="img-slider/arrow-left.png" alt="left arrow" class="prev"> <div class="slider-inner"> <img src="img-slider/john-jpg.jpg" class="active" alt=""> <img src="img-slider/butterflies-jpg.jpg" alt=""> <img src="img-slider/andrew-jpg.jpg" alt=""> <img src="img-slider/taylor-jpg.jpg" alt=""> </div> <img src="img-slider/arrow-right.png" alt="next arrow" class="next"> </div> </div> <script src="javascript/jquery.js"></script> <script src="javascript/main.js"></script> </body> </html>

此处don't work for me in LINQPad的版本(在 LINQPad 5 和 LINQPad 6 上测试)

代码

work in LINQPad

答案 10 :(得分:0)

您还可以使用在.net5中测试的EF功能

public async Task<IEnumerable<District>> SearchDistrict(string query, int stateId)
        {
            return await _dbContext
                .Districts
                .Include(s => s.State)
                .Where(s => s.StateId == stateId && EF.Functions.Like(s.Name, "$%{query}%"))
                .AsNoTracking()
                .ToListAsync();
        }

答案 11 :(得分:0)

类似于扩展名Linq / SQL

LikeExtension类

在.NET 5中测试

 public static class LikeExtension {

    private static string ColumnDataBase<TEntity, TKey>(IModel model, Expression<Func<TEntity, TKey>> predicate) where TEntity : class {

        ITable table = model
            .GetRelationalModel()
            .Tables
            .First(f => f
                .EntityTypeMappings
                .First()
                .EntityType == model
                .FindEntityType(predicate
                    .Parameters
                    .First()
                .Type
            ));

        string column = (predicate.Body as MemberExpression).Member.Name;
        string columnDataBase = table.Columns.First(f => f.PropertyMappings.Count(f2 => f2.Property.Name == column) > 0).Name;

        return columnDataBase;

    }

    public static IQueryable<TEntity> Like<TEntity, TKey>(this DbContext context, Expression<Func<TEntity, TKey>> predicate, string text) where TEntity : class {

        string columnDataBase = ColumnDataBase(context.Model, predicate);
        return context.Set<TEntity>().FromSqlRaw(context.Set<TEntity>().ToQueryString() + " WHERE [" + columnDataBase + "] LIKE {0}", text);

    }

    public static async Task<IEnumerable<TEntity>> LikeAsync<TEntity, TKey>(this DbContext context, Expression<Func<TEntity, TKey>> predicate, string text, CancellationToken cancellationToken) where TEntity : class {

        string columnDataBase = ColumnDataBase(context.Model, predicate);
        return await context.Set<TEntity>().FromSqlRaw(context.Set<TEntity>().ToQueryString() + " WHERE [" + columnDataBase + "] LIKE {0}", text).ToListAsync(cancellationToken);

    }

    public static async Task<IEnumerable<TEntity>> LikeAsync<TEntity, TKey>(this IQueryable<TEntity> query, Expression<Func<TEntity, TKey>> predicate, string text, CancellationToken cancellationToken) where TEntity : class {

        DbSet<TEntity> entities = query as DbSet<TEntity>;
        string columnDataBase = ColumnDataBase(entities.EntityType.Model, predicate);
        return await entities.FromSqlRaw(query.ToQueryString() + " WHERE [" + columnDataBase + "] LIKE {0}", text).ToListAsync(cancellationToken);

    }

    public static IQueryable<TEntity> Like<TEntity, TKey>(this IQueryable<TEntity> query, Expression<Func<TEntity, TKey>> predicate, string text) where TEntity : class {

        DbSet<TEntity> entities = query as DbSet<TEntity>;
        string columnDataBase = ColumnDataBase(entities.EntityType.Model, predicate);
        return entities.FromSqlRaw(query.ToQueryString() + " WHERE [" + columnDataBase + "] LIKE {0}", text);

    }

}

存储库

    public async Task<IEnumerable<TEntity>> LikeAsync<TKey>(Expression<Func<TEntity, TKey>> predicate, string text, CancellationToken cancellationToken) {

        return await context.LikeAsync(predicate, text, cancellationToken);

    }

    public IQueryable<TEntity> Like<TKey>(Expression<Func<TEntity, TKey>> predicate, string text) {

        return context.Like(predicate, text);

    }

使用

 IQueryable<CountryEntity> result = countryRepository
     .Like(k => k.Name, "%Bra[sz]il%") /*Use Sync*/
     .Where(w => w.DateRegister < DateTime.Now) /*Example*/
     .Take(10); /*Example*/

 IEnumerable<CountryEntity> result = await countryRepository
     .LikeAsync(k => k.Name, "%Bra[sz]il%", cancellationToken); /*Use Async*/

 IQueryable<CountryEntity> result = context.Countries
     .Like(k => k.Name, "%Bra[sz]il%")
     .Where(w => w.Name != null); /*Example*/

 List<CountryEntity> result2 = await context.Countries
     .Like(k => k.Name, "%Bra[sz]il%")
     .Where(w => w.Name != null) /*Example*/
     .ToListAsync(); /*Use Async*/

 IEnumerable<CountryEntity> result3 = await context.Countries
     .Where(w => w.Name != null)
     .LikeAsync(k => k.Name, "%Bra[sz]il%", cancellationToken); /*Use Async*/

答案 12 :(得分:0)

@adobrzyc具有出色的自定义LIKE函数-我只想共享它的IEnumerable版本。

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) });

    private static 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).Compile();
    }

    public static IEnumerable<TSource> Like<TSource, TMember>(this IEnumerable<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;
    }
}

答案 13 :(得分:0)

List<Categories> categoriess;
        private void Buscar()
        {
            try
            {
                categoriess = Contexto.Categories.ToList();
                categoriess = categoriess.Where(n => n.CategoryID >= Convert.ToInt32(txtCatID.Text) && n.CategoryID <= Convert.ToInt32(txtCatID1.Text) && (n.CategoryName.Contains(txtCatName.Text)) ).ToList();

答案 14 :(得分:0)

我找到了一个模仿SQL LIKE运算符的解决方案。请参阅我在这里写的答案 https://stackoverflow.com/a/46592475/1186073

答案 15 :(得分:0)

只需添加到字符串对象扩展方法即可。

public static class StringEx
{
    public static bool Contains(this String str, string[] Arr, StringComparison comp)
    {
        if (Arr != null)
        {
            foreach (string s in Arr)
            {
                if (str.IndexOf(s, comp)>=0)
                { return true; }
            }
        }

        return false;
    }

    public static bool Contains(this String str,string[] Arr)
    {
        if (Arr != null)
        {
            foreach (string s in Arr)
            {
                if (str.Contains(s))
                { return true; }
            }
        }

        return false;
    }
}

用法:

use namespase that contains this class;

var sPortCode = Database.DischargePorts
            .Where(p => p.PortName.Contains(new string [] {"BALTIMORE"},  StringComparison.CurrentCultureIgnoreCase) )
            .Single().PortCode;

答案 16 :(得分:0)

   public static class StringEx
    {
        public static bool Contains(this String str, string[] Arr, StringComparison comp)
        {
            if (Arr != null)
            {
                foreach (string s in Arr)
                {
                    if (str.IndexOf(s, comp)>=0)
                    { return true; }
                }
            }

            return false;
        }

        public static bool Contains(this String str,string[] Arr)
        {
            if (Arr != null)
            {
                foreach (string s in Arr)
                {
                    if (str.Contains(s))
                    { return true; }
                }
            }

            return false;
        }
    }


var portCode = Database.DischargePorts
                   .Single(p => p.PortName.Contains( new string[] {"BALTIMORE"},  StringComparison.CurrentCultureIgnoreCase) ))
                   .PortCode;