it-swarm.com.de

Wie Operator im Entity Framework?

Wir versuchen, den Entsprechungsoperator "LIKE" in Entity Framework für unsere Entitäten mit String-Feldern zu implementieren, es scheint jedoch nicht unterstützt zu werden. Hat jemand anderes versucht, so etwas zu tun?

Dieser Blogbeitrag fasst das Problem zusammen, das wir haben. Wir könnten enthalten verwenden, aber das trifft nur auf den trivialsten Fall für LIKE zu. Das Kombinieren von enthält, startswith, endswith und indexof bringt uns dorthin, erfordert jedoch eine Übersetzung zwischen Standard-Wildcards und Linq to Entities-Code.

79
brien

Dies ist jetzt ein alter Beitrag, aber für jeden, der nach der Antwort sucht, sollte dieser Link helfen.

Kurze Version:

SqlFunctions.PatIndex - Methode - Gibt die Startposition des ersten Vorkommens eines Musters in einem angegebenen Ausdruck zurück oder Nullen, wenn das Muster nicht gefunden wird, für alle gültigen Text- und Zeichendatentypen

Namespace: System.Data.Objects.SqlClient Assembly: System.Data.Entity (in System.Data.Entity.dll)

Eine kleine Erklärung erscheint auch in diesem Forumsthread .

28
Yann Duran

Ich kenne eigentlich nichts über EF, aber in LINQ to SQL formulieren Sie normalerweise eine LIKE-Klausel mit String.Contains:

where entity.Name.Contains("xyz")

wird übersetzt in

WHERE Name LIKE '%xyz%'

(Verwenden Sie StartsWith und EndsWith für anderes Verhalten.)

Ich bin nicht ganz sicher, ob das hilfreich ist, denn ich verstehe nicht, was Sie meinen, wenn Sie sagen, Sie versuchen, implementieren LIKE. Wenn ich mich völlig falsch verstanden habe, lass es mich wissen und ich lösche diese Antwort :)

142
Jon Skeet

Ich hatte das gleiche Problem. 

Im Moment habe ich mich mit der clientseitigen Wildcard/Regex-Filterung basierend auf http://www.codeproject.com/Articles/11556/Converting-Wildcards-to-Regexes?msg=1423024#xx1423024xx - entschieden einfach und funktioniert wie erwartet.

Ich habe eine andere Diskussion zu diesem Thema gefunden: http://forums.asp.net/t/1654093.aspx/2/10
Dieser Beitrag sieht vielversprechend aus, wenn Sie Entity Framework> = 4.0 verwenden:

Verwenden Sie SqlFunctions.PatIndex:

http://msdn.Microsoft.com/de-de/library/system.data.objects.sqlclient.sqlfunctions.patindex.aspx

So was:

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

Hinweis: Diese Lösung ist nur für SQL-Server, da sie nicht standardmäßige PATINDEX-Funktionen verwendet.

32
surfen

Update: In EF 6.2 gibt es einen Like-Operator

Where(i => DbFunctions.Like(searchstring ,like expression)
14
Lode Vlaeminck

In Entity Framework Core 2.0 wird der Operator LIKE hinzugefügt:

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

Im Vergleich zu ... where e.Title.Contains("developer") ... wird es wirklich in SQLLIKE übersetzt, anstatt in CHARINDEX, die wir für Contains-Methode sehen.

9
Dmitry Pavlov

Sie wird in der Dokumentation als Teil von Entity SQL ausdrücklich erwähnt. Bekommen Sie eine Fehlermeldung?

// 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/de-de/library/bb399359.aspx

5
Robert Harvey

wenn Sie MS SQL verwenden, habe ich 2 Erweiterungsmethoden geschrieben, um das% -Zeichen für die Platzhaltersuche zu unterstützen. (LinqKit ist erforderlich)

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

verwendungszweck

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

in ef6 und es sollte zu übersetzen 

....
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 '

2
Steven Chong

Für EfCore ist hier ein Beispiel zum Erstellen eines LIKE-Ausdrucks

protected override Expression<Func<YourEntiry, bool>> BuildLikeExpression(string searchText)
    {
        var likeSearch = $"%{searchText}%";

        return t => EF.Functions.Like(t.Code, likeSearch)
                    || EF.Functions.Like(t.FirstName, likeSearch)
                    || EF.Functions.Like(t.LastName, likeSearch);
    }

//Calling method

var query = dbContext.Set<YourEntity>().Where(BuildLikeExpression("Text"));
1
Duy Hoang

Sie können einen Real wie in Link to Entities verwenden

Hinzufügen

    <Function Name="String_Like" ReturnType="Edm.Boolean">
      <Parameter Name="searchingIn" Type="Edm.String" />
      <Parameter Name="lookingFor" Type="Edm.String" />
      <DefiningExpression>
        searchingIn LIKE lookingFor
      </DefiningExpression>
    </Function>

zu Ihrem EDMX in diesem Tag: 

edmx: Edmx/edmx: Laufzeit/edmx: ConceptualModels/Schema

Denken Sie auch an den Namespace im <schema namespace="" />-Attribut

Fügen Sie dann eine Erweiterungsklasse im obigen Namespace hinzu:

public static class Extensions
{
    [EdmFunction("DocTrails3.Net.Database.Models", "String_Like")]
    public static Boolean Like(this String searchingIn, String lookingFor)
    {
        throw new Exception("Not implemented");
    }
}

Diese Erweiterungsmethode wird jetzt der EDMX-Funktion zugeordnet.

Mehr Infos hier: http://jendaperl.blogspot.be/2011/02/like-in-linq-to-entities.html

0
brechtvhb

re: "Wir möchten auf blah blah foo bar foo? bar? foo * bar? und anderen komplexen Mustern passen." Ich habe das eigentlich nicht probiert (nicht nötig) bis jetzt), aber haben Sie versucht, System.Text.RegularExpressions.RegEx zu verwenden?

0
th2tran