LINQ में LIKE ऑपरेटर


89

एसक्यूएल के LIKEऑपरेटर के समान C # LINQ अभिव्यक्ति में तार की तुलना करने का कोई तरीका है ?

मान लीजिए कि मेरे पास एक स्ट्रिंग सूची है। इस सूची में मैं एक स्ट्रिंग खोजना चाहता हूं। SQL में, मैं लिख सकता था:

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

उपरोक्त के बजाय, क्वेरी एक लाइन सिंटैक्स चाहती है।

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 प्रदाता में कार्यान्वयन अंतर हैं ... वैसे भी, धन्यवाद।
मार्क Ewer

यह सबसे अच्छा समाधान है जिसे मैंने LINQ में पसंद किया है। धन्यवाद। - @ प्रणय-राणा
अभिषेक तोमर

जवाबों:


142

आमतौर पर आप String.StartsWith/ EndsWith/ का उपयोग करते हैं Contains। उदाहरण के लिए:

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

मुझे नहीं पता कि वहाँ LINQ के माध्यम से SQL के लिए उचित नियमित अभिव्यक्ति करने का एक तरीका है। (ध्यान दें कि यह वास्तव में इस बात पर निर्भर करता है कि आप किस प्रदाता का उपयोग कर रहे हैं - यह LINQ में ऑब्जेक्ट्स के लिए ठीक होगा; यह बात है कि क्या प्रदाता कॉल को अपने मूल क्वेरी प्रारूप, जैसे SQL में परिवर्तित कर सकता है।)

EDIT: जैसा कि BitKFu कहता है, Singleका उपयोग तब किया जाना चाहिए जब आप बिल्कुल एक परिणाम की उम्मीद करते हैं - जब यह एक त्रुटि है कि ऐसा न हो। के विकल्प SingleOrDefault, FirstOrDefaultया Firstके आधार पर इस्तेमाल किया जाना चाहिए वास्तव में क्या उम्मीद है।


मित्र लेकिन, एक समस्या है, मेरी सूची में "BALTIMORE" है, और मेरा दिया गया तुलना पैरामीटर "BALTIMORE [MD], US" है। मेरे वाक्य विन्यास का चयन करने में विफल रहें।
शमीम

2
नीचे मेरे कथन पर एक नज़र डालें, यह एकल () विधि से आ सकता है। FirstOrDefault ()
BitKFu

3
@ शमीम: तो आपके डेटा में वह स्ट्रिंग नहीं है जिसकी आप तलाश कर रहे हैं? आप एसक्यूएल में भी कैसे काम करने की उम्मीद करेंगे?
जॉन स्कीट

SQL में आपको कोई परिणाम सेट नहीं मिल सकता है - C # में आपको एक अपवाद मिलेगा। जो बिना किसी नतीजे के थोड़ा अलग है। इसलिए मैंने FirstOrDefault का उपयोग करने की सिफारिश की है।
बिटकॉफ

की एक प्रारंभिक बिंदु से @BitKFu Single(), SingleOrDefault(), मेरे अगले कदम होगा जब तक कि हम पूरे संदर्भ को समझने ...
मार्क Gravell

34

Regex? नहीं। लेकिन उस क्वेरी के लिए आप बस उपयोग कर सकते हैं:

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

यदि आप वास्तव में SQL चाहते हैं LIKE, तो आप SQL Server में System.Data.Linq.SqlClient.SqlMethods.Like(...)LINQ-to-SQL मैप्स का उपयोग कर सकते हैं LIKE


@ मैस्लो - मेरी विशेषज्ञता का क्षेत्र नहीं, मुझे डर है - लेकिन मुझे विश्वास नहीं है कि मैपिंग का एक अच्छा साफ तरीका है कि सभी ईएफ कार्यान्वयनों के लिए, इसलिए ... नहीं।
मार्क Gravell

2
यह एसक्यूएल कार्यान्वयन पर काम कर सकता है लेकिन एक मानक ऑब्जेक्ट संग्रह के साथ काम नहीं करता है
क्रिस मैकग्राथ

13

खैर ... कभी-कभी यह उपयोग करने के लिए असुविधाजनक हो सकता है Contains, StartsWithया EndsWithविशेष रूप से जब मूल्य निर्धारित करने के लिए खोज निर्धारित किया जाता है LIKEजैसे कि 'मान%' को डेवलपर से 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?
निके मैनारिन

8

जैसा कि जॉन स्कीट और मार्क ग्रेवेल ने पहले ही उल्लेख किया है, आप एक शर्त को सरल रूप से ले सकते हैं। लेकिन आपके प्रश्न की तरह, सिंगल () स्टेटमेंट लेना बहुत खतरनाक है, क्योंकि इसका मतलब है कि आपको केवल 1 परिणाम मिलेगा। अधिक परिणामों के मामले में, आपको एक अच्छा अपवाद प्राप्त होगा :)

इसलिए मैं Single () के बजाय FirstOrDefault () का उपयोग करना पसंद करूंगा:

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

यदि यह हमारी पूरी उम्मीद है कि वास्तव में एक मैच है, तो सिंगल "खतरनाक" नहीं है - यह "सही" है। यह सब "कम से कम एक", "सबसे एक में", "एक ही", आदि हम क्या डेटा ... "किसी भी संख्या" के बारे में दावा कर रहे हैं करने के लिए नीचे आता है,
मार्क Gravell

3
संदर्भ के आधार पर, यह हो सकता है ... यह क्वेरी की उम्मीद पर पूरी तरह से निर्भर
मार्क Gravell

"खाली" या "%" खोज के बारे में क्या? क्या यह "B", "BALT" और "" (मतलब मुझे सब कुछ मिल सकता है) को संभाल सकता है?
ब्लूचिप्पी

8

मूल LINQ में आप Contains/StartsWith/EndsWithया RegExp के संयोजन का उपयोग कर सकते हैं ।

LINQ2SQL उपयोग विधि में SqlMethods.Like()

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

इस सुविधा का उपयोग करने के लिए असेंबली जोड़ें: System.Data.Linq (System.Data.Linq.dll में)।


मैं समझता हूं कि ओपी ने वास्तव में Linq2SQL नहीं कहा था , लेकिन यह निहित था। कारण मैं यहाँ हूँ वह यह है कि StartsWith(), Contains(), आदि, करते नहीं Linq2SQL (साथ काम कम से कम मैं "LINQ अभिव्यक्ति ... अनुवाद नहीं किया जा सकता है ..." और उपयोग ToList को एक निर्देश () "ग्राहक मूल्यांकन के लिए" -which मैं ' मी पहले से ही कर रहा है। नोट, EF कोर में, इसे स्थानांतरित कर दिया गया हैEF.Functions.Like()
Auspex

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

यह SQL के "LIKE" की तरह काम करता है ...


8
नहीं .. नहीं, यह केवल LIKE 'टर्म%' की तरह काम नहीं करता है, जो पूरी तरह से ऑपरेटर की तरह काम करने से दूर है और वाइल्डकार्ड का समर्थन नहीं करता है
क्रिस मैकग्राथ

3

इस के रूप में एक सरल

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

परिणाम -> एनिक, यानिक


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

@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;
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.