LINQ의 LIKE 연산자


89

SQL의 LIKE연산자 와 유사한 C # LINQ 식의 문자열을 비교할 수있는 방법이 있습니까?

문자열 목록이 있다고 가정합니다. 이 목록에서 문자열을 검색하고 싶습니다. 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 구문이 작동하지 않습니다. 내가 뭘 잘못 했니?


1
이 쿼리는 기본적으로 저에게 효과적이었습니다. 하지만 저는 MongoDb Linq 드라이버를 사용하고 있으며 각 Linq 공급자마다 구현 차이가 있습니다. 어쨌든 감사합니다.
Mark Ewer 2013 년

이것은 LINQ에서 찾은 최고의 솔루션입니다. 감사. -@ Pranay-Rana
Abhishek Tomar

답변:


142

일반적으로 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


친구이지만 문제가 하나 있습니다. 내 목록에 "BALTIMORE"가 포함되어 있고 내가 지정한 비교 매개 변수는 "BALTIMORE [MD], US"입니다. 위의 구문을 선택하지 못했습니다.
shamim 2011 년

2
아래 내 진술을 살펴보면 Single () 메서드에서 올 수 있습니다. 그것은 FirstOrDefault ()를 사용하는 것이 좋습니다
BitKFu

3
@shamim : 데이터에 찾고있는 문자열이 포함되어 있지 않습니까? SQL에서도 어떻게 작동 할 것으로 기대하십니까?
Jon Skeet 2011 년

SQL에서는 결과 집합이 없을 수 있습니다. C #에서는 예외가 발생합니다. 결과가 아니라 약간 다릅니다. 그래서 FirstOrDefault를 사용하는 것이 좋습니다.
BitKFu 2011 년

의 시작 지점에서 @BitKFu은 Single(), SingleOrDefault()우리가 ... 전체 맥락을 이해하지 않는 한, 나의 다음 단계가 될 것입니다
마크 Gravell

34

정규식? 아니. 그러나 해당 쿼리의 경우 다음을 사용할 수 있습니다.

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

당신이 경우 실제로 SQL을 원하는 LIKE, 당신이 사용할 수있는 System.Data.Linq.SqlClient.SqlMethods.Like(...)LINQ - 투 - SQL에 매핑되는 LIKESQL Server의.


@Maslow-내 전문 분야가 아닙니다. 두렵습니다.하지만 모든 EF 구현에 매핑하는 깔끔한 방법이 없다고 믿습니다.
Marc Gravell

2
이것은 SQL 구현에서는 작동 할 수 있지만 표준 개체 컬렉션에서는 작동하지 않습니다.
Chris McGrath

13

글쎄 ... 때로는 사용하기가 불편할 수 있습니다 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

암호

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

와 함께 작동하는 버전이 IEnumerable있습니까?
Nicke Manarin

8

Jon Skeet과 Marc Gravell이 이미 언급했듯이 포함 조건을 간단히 취할 수 있습니다. 그러나 같은 쿼리의 경우 Single () 문을 사용하는 것은 매우 위험합니다. 그 이유는 결과가 1 개뿐임을 의미하기 때문입니다. 더 많은 결과의 경우 멋진 예외를 받게됩니다. :)

따라서 Single () 대신 FirstOrDefault ()를 사용하는 것이 좋습니다.

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

정확히 하나의 일치가 있다는 것이 우리의 주장 이라면 Single은 "위험한"것이 아니라 "올바른"것입니다. 모든 것은 데이터에 대해 우리가 주장하는 내용으로 귀결됩니다. "모든 숫자", "적어도 하나", "최대 1 개", "정확히 하나"등
Marc Gravell

3
상황에 따라서는 할 수있다 ... 그것은 쿼리의 기대에 전적으로 달려있다
마크 Gravell

"빈"또는 "%"검색은 어떻습니까? "B", "BALT"및 ""(모든 것을 얻을 수 있음을 의미)를 처리 할 수 ​​있습니까?
BlueChippy 2011 년

8

네이티브 LINQ에서는 Contains/StartsWith/EndsWith또는 RegExp의 조합을 사용할 수 있습니다 .

LINQ2SQL 사용 방법 SqlMethods.Like()

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

이 기능을 사용하려면 Assembly : System.Data.Linq (System.Data.Linq.dll에 있음)를 추가합니다.


나는 OP가 실제로 Linq2SQL을 말하지 않았 음을 이해 하지만 암시 적으로 보였습니다. 내가 여기있는 이유는 즉 StartsWith(), Contains()등이 수행 되지 Linq2SQL (과 작업 적어도 내가 얻을 ... "... LINQ 식을 변환 할 수 없습니다" 와 "클라이언트 평가"에 대한 사용 ToList에 대한 명령 () - 어떤 I ' m 이미 수행 중입니다. 참고, EF Core에서는EF.Functions.Like()
Auspex

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

이것은 SQL의 "LIKE"처럼 작동합니다.


8
아니요 .. 아니요 전체적으로 like 연산자처럼 작동하는 것과는 거리가 멀고 와일드 카드를 지원하지 않는 LIKE 'term %'처럼 작동하지 않습니다
Chris McGrath

3

이처럼 간단

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

결과-> Annick, Yannick


2

조건 자와 함께 단일 메서드를 호출 할 수 있습니다.

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

2

이상적으로는 StartWith또는 EndWith.

예를 들면 다음과 같습니다.

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

return lstPerson;

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;

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;

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


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;
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.