[.net] Entity Framework의 연산자처럼?

문자열 필드가있는 엔터티에 대해 Entity Framework에서 “LIKE”연산자를 구현하려고하지만 지원되지 않는 것 같습니다. 다른 사람이 이와 같은 작업을 시도한 적이 있습니까?

블로그 게시물 은 우리가 겪고있는 문제를 요약합니다. contains를 사용할 수 있지만 LIKE의 가장 사소한 경우에만 일치합니다. contains, startswith, endswith 및 indexof를 결합하면 표준 와일드 카드와 Linq를 엔티티 코드로 변환해야합니다.



답변

이것은 현재 오래된 게시물이지만 답변을 찾는 사람에게는 이 링크 가 도움이 될 것입니다. 이미 EF 6.2.x를 사용중인 경우이 답변으로 이동하십시오 . 에 이 답변 당신은 EF 코어 2.X를 사용하는 경우

짧은 버전 :

SqlFunctions.PatIndex 메서드-모든 유효한 텍스트 및 문자 데이터 형식에서 지정된 식에서 패턴이 처음 나타나는 시작 위치를 반환하거나 패턴이없는 경우 0을 반환합니다.

네임 스페이스 : System.Data.Objects.SqlClient 어셈블리 : System.Data.Entity (System.Data.Entity.dll에 있음)

포럼 스레드 에도 약간의 설명이 표시됩니다 .


답변

EF에 대해 실제로는 모르지만 LINQ to SQL에서는 일반적으로 String.Contains를 사용하여 LIKE 절을 표현합니다.

where entity.Name.Contains("xyz")

번역하다

WHERE Name LIKE '%xyz%'

( StartsWithEndsWith기타 동작에 사용하십시오 .)

LIKE 를 구현 하려고 할 때 의미하는 바를 이해하지 못하기 때문에 이것이 도움이되는지 확실하지 않습니다 . 내가 완전히 오해했다면 알려 주시면이 답변을 삭제하겠습니다 🙂


답변

나는 같은 문제가 있었다.

지금은 http://www.codeproject.com/Articles/11556/Converting-Wildcards-to-Regexes?msg=1423024#xx1423024xx를 기반으로 클라이언트 측 Wildcard / Regex 필터링을 사용했습니다 . 간단하고 다음과 같이 작동합니다. 예상됩니다.

이 주제에 대한 또 다른 토론을 찾았습니다. http://forums.asp.net/t/1654093.aspx/2/10
이 게시물은 Entity Framework> = 4.0을 사용하는 경우 유망 해 보입니다.

SqlFunctions.PatIndex 사용 :

http://msdn.microsoft.com/en-us/library/system.data.objects.sqlclient.sqlfunctions.patindex.aspx

이렇게 :

var q = EFContext.Products.Where(x =>
SqlFunctions.PatIndex("%CD%BLUE%", x.ProductName) > 0);

참고 :이 솔루션은 비표준 PATINDEX 함수를 사용하기 때문에 SQL-Server 전용입니다.


답변

업데이트 : EF 6.2에는 like 연산자가 있습니다.

Where(obj => DbFunctions.Like(obj.Column , "%expression%")


답변

거기에 LIKE운영자가 추가됩니다 Entity Framework Core 2.0:

var query = from e in _context.Employees
                    where EF.Functions.Like(e.Title, "%developer%")
                    select e;

... where e.Title.Contains("developer") ...그것과 비교하는 것은 우리가 방법으로 보는 SQL LIKE것보다 실제로 번역되었습니다 .CHARINDEXContains


답변

특히 Entity SQL의 일부로 설명서에 언급되어 있습니다. 오류 메시지가 표시됩니까?

// LIKE and ESCAPE
// If an AdventureWorksEntities.Product contained a Name
// with the value 'Down_Tube', the following query would find that
// value.
Select value P.Name FROM AdventureWorksEntities.Product
    as P where P.Name LIKE 'DownA_%' ESCAPE 'A'

// LIKE
Select value P.Name FROM AdventureWorksEntities.Product
    as P where P.Name like 'BB%'

http://msdn.microsoft.com/en-us/library/bb399359.aspx


답변

MS Sql을 사용하는 경우 와일드 카드 검색을 위해 % 문자를 지원하는 두 가지 확장 메서드를 작성했습니다. (LinqKit이 필요합니다)

public static class ExpressionExtension
{
    public static Expression<Func<T, bool>> Like<T>(Expression<Func<T, string>> expr, string likeValue)
    {
        var paramExpr = expr.Parameters.First();
        var memExpr = expr.Body;

        if (likeValue == null || likeValue.Contains('%') != true)
        {
            Expression<Func<string>> valExpr = () => likeValue;
            var eqExpr = Expression.Equal(memExpr, valExpr.Body);
            return Expression.Lambda<Func<T, bool>>(eqExpr, paramExpr);
        }

        if (likeValue.Replace("%", string.Empty).Length == 0)
        {
            return PredicateBuilder.True<T>();
        }

        likeValue = Regex.Replace(likeValue, "%+", "%");

        if (likeValue.Length > 2 && likeValue.Substring(1, likeValue.Length - 2).Contains('%'))
        {
            likeValue = likeValue.Replace("[", "[[]").Replace("_", "[_]");
            Expression<Func<string>> valExpr = () => likeValue;
            var patExpr = Expression.Call(typeof(SqlFunctions).GetMethod("PatIndex",
                new[] { typeof(string), typeof(string) }), valExpr.Body, memExpr);
            var neExpr = Expression.NotEqual(patExpr, Expression.Convert(Expression.Constant(0), typeof(int?)));
            return Expression.Lambda<Func<T, bool>>(neExpr, paramExpr);
        }

        if (likeValue.StartsWith("%"))
        {
            if (likeValue.EndsWith("%") == true)
            {
                likeValue = likeValue.Substring(1, likeValue.Length - 2);
                Expression<Func<string>> valExpr = () => likeValue;
                var containsExpr = Expression.Call(memExpr, typeof(String).GetMethod("Contains",
                    new[] { typeof(string) }), valExpr.Body);
                return Expression.Lambda<Func<T, bool>>(containsExpr, paramExpr);
            }
            else
            {
                likeValue = likeValue.Substring(1);
                Expression<Func<string>> valExpr = () => likeValue;
                var endsExpr = Expression.Call(memExpr, typeof(String).GetMethod("EndsWith",
                    new[] { typeof(string) }), valExpr.Body);
                return Expression.Lambda<Func<T, bool>>(endsExpr, paramExpr);
            }
        }
        else
        {
            likeValue = likeValue.Remove(likeValue.Length - 1);
            Expression<Func<string>> valExpr = () => likeValue;
            var startsExpr = Expression.Call(memExpr, typeof(String).GetMethod("StartsWith",
                new[] { typeof(string) }), valExpr.Body);
            return Expression.Lambda<Func<T, bool>>(startsExpr, paramExpr);
        }
    }

    public static Expression<Func<T, bool>> AndLike<T>(this Expression<Func<T, bool>> predicate, Expression<Func<T, string>> expr, string likeValue)
    {
        var andPredicate = Like(expr, likeValue);
        if (andPredicate != null)
        {
            predicate = predicate.And(andPredicate.Expand());
        }
        return predicate;
    }

    public static Expression<Func<T, bool>> OrLike<T>(this Expression<Func<T, bool>> predicate, Expression<Func<T, string>> expr, string likeValue)
    {
        var orPredicate = Like(expr, likeValue);
        if (orPredicate != null)
        {
            predicate = predicate.Or(orPredicate.Expand());
        }
        return predicate;
    }
}

용법

var orPredicate = PredicateBuilder.False<People>();
orPredicate = orPredicate.OrLike(per => per.Name, "He%llo%");
orPredicate = orPredicate.OrLike(per => per.Name, "%Hi%");

var predicate = PredicateBuilder.True<People>();
predicate = predicate.And(orPredicate.Expand());
predicate = predicate.AndLike(per => per.Status, "%Active");

var list = dbContext.Set<People>().Where(predicate.Expand()).ToList();

ef6에서 다음으로 번역되어야합니다.

....
from People per
where (
    patindex(@p__linq__0, per.Name) <> 0
    or per.Name like @p__linq__1 escape '~'
) and per.Status like @p__linq__2 escape '~'

‘, @ p__linq__0 =’% He % llo % ‘, @ p__linq__1 =’% Hi % ‘, @ p__linq_2 =’% Active ‘