LINQ中的LIKE运算符

sha*_*mim 84 c# linq sql-like

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

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

SELECT * FROM DischargePort WHERE PortName LIKE '%BALTIMORE%'
Run Code Online (Sandbox Code Playgroud)

而不是上述,查询需要linq语法.

using System.Text.RegularExpressions;
…

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

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

Jon*_*eet 131

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

var portCode = Database.DischargePorts
                       .Where(p => p.PortName.Contains("BALTIMORE"))
                       .Single()
                       .PortCode;
Run Code Online (Sandbox Code Playgroud)

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

编辑:正如BitKFu所说,Single当你期望一个结果时应该使用- 当它出现错误时就不会出现这种情况.的选项SingleOrDefault,FirstOrDefaultFirst应视使用究竟要的是什么.

  • @shamim:所以你的数据不包含你正在寻找的字符串?您如何期望即使在SQL中也能工作? (3认同)
  • 看看我下面的语句,它可能来自 Single() 方法。最好使用 FirstOrDefault() (2认同)

Mar*_*ell 30

正则表达式?没有.但对于该查询,您可以使用:

 string filter = "BALTIMORE";
 (blah) .Where(row => row.PortName.Contains(filter)) (blah)
Run Code Online (Sandbox Code Playgroud)

如果你真的想要SQL LIKE,你可以使用System.Data.Linq.SqlClient.SqlMethods.Like(...)哪些LINQ-to-SQL映射到LIKESQL Server.

  • 这可能适用于 SQL 实现,但不适用于标准对象集合 (2认同)

ado*_*zyc 10

嗯...有时候使用它可能会让人感到不舒服Contains,StartsWith或者EndsWith特别是在搜索值时确定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
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Bit*_*KFu 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;
Run Code Online (Sandbox Code Playgroud)

  • 取决于上下文,它可以...它完全取决于查询的期望 (3认同)

Mar*_*bad 7

在本机LINQ中,您可以使用Contains/StartsWith/EndsWith或RegExp的组合.

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

    from i in db.myTable
    where SqlMethods.Like(i.field, "tra%ata")
    select i
Run Code Online (Sandbox Code Playgroud)

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