webentwicklung-frage-antwort-db.com.de

LIKE-Operator in LINQ

Gibt es eine Möglichkeit, Zeichenfolgen in einem C # LINQ-Ausdruck zu vergleichen, der dem SQL-Operator LIKE ähnelt?

Angenommen, ich habe eine String-Liste. Auf dieser Liste möchte ich eine Zeichenfolge suchen. In SQL könnte ich schreiben:

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

Anstelle der oben genannten möchten Abfrage eine Linq-Syntax.

using System.Text.RegularExpressions;
…

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

Meine obige LINQ-Syntax funktioniert nicht. Was habe ich falsch gemacht?

82
shamim

Normalerweise verwenden Sie String.StartsWith/EndsWith/Contains. Beispielsweise:

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

Ich weiß jedoch nicht, ob es eine Möglichkeit gibt, reguläre Ausdrücke über LINQ to SQL zu erstellen. (Beachten Sie, dass dies wirklich von dem von Ihnen verwendeten Anbieter abhängt. In LINQ to Objects ist dies in Ordnung. Es hängt davon ab, ob der Anbieter den Aufruf in sein systemeigenes Abfrageformat, beispielsweise SQL, konvertieren kann.)

EDIT: Wie BitKFu sagt, sollte Single verwendet werden, wenn Sie erwarten, dass genau ein Ergebnis - wenn es ein Fehler ist, dass dies nicht der Fall ist. Optionen von SingleOrDefault, FirstOrDefault oder First sollten verwendet werden, abhängig von gena was erwartet wird.

130
Jon Skeet

Regex? Nein. Aber für diese Abfrage können Sie einfach verwenden:

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

Wenn Sie wirklich SQL LIKE wollen, können Sie System.Data.Linq.SqlClient.SqlMethods.Like(...) , welches LINQ-to-SQL in SQL Server LIKE zuordnet.

30
Marc Gravell

Nun, manchmal kann es unangenehm sein, Contains, StartsWith oder EndsWith zu verwenden, insbesondere wenn der Suchwert den LIKE -Statement bestimmt, z. Der übergebene 'Wert%' verlangt vom Entwickler die Verwendung der Funktion StartsWith im Ausdruck. Also habe ich beschlossen, eine Erweiterung für IQueryable -Objekte zu schreiben.

Verwendung

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

Code

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

Wie Jon Skeet und Marc Gravell bereits erwähnt haben, können Sie einfach eine Contained-Bedingung annehmen. Im Falle einer ähnlichen Abfrage ist es jedoch sehr gefährlich, eine Single () - Anweisung zu verwenden, da dies impliziert, dass Sie nur 1 Ergebnis finden. Bei mehr Ergebnissen erhalten Sie eine nette Ausnahme :)

Daher würde ich FirstOrDefault () anstelle von Single () bevorzugen:

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

In nativem LINQ können Sie eine Kombination aus Contains/StartsWith/EndsWith Oder RegExp verwenden.

Verwenden Sie in LINQ2SQL die Methode SqlMethods.Like()

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

fügen Sie Assembly: System.Data.Linq (in System.Data.Linq.dll) hinzu, um diese Funktion zu verwenden.

7

So einfach ist das

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

Ergebnis -> Annick, Yannick

3
Yannick Turbang

Sie können die einzelne Methode mit einem Prädikat aufrufen:

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

Idealerweise sollten Sie StartWith oder EndWith verwenden.

Hier ist ein Beispiel:

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

return lstPerson;
  .Where(e => e.Value.StartsWith("BALTIMORE"))

Das funktioniert wie "LIKE" von SQL ...

2
user1930698
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
Eber Camacho

Ich habe eine Lösung gefunden, um den SQL LIKE-Operator nachzuahmen. Beziehen Sie sich auf die Antwort, die ich hier geschrieben habe https://stackoverflow.com/a/46592475/118607

0
Hugo
   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
NoBrend s

Fügen Sie einfach den String-Objekterweiterungsmethoden hinzu.

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

verwendung:

use namespase that contains this class;

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