इकाई ढांचे में ऑपरेटर की तरह?


92

हम स्ट्रिंग क्षेत्रों के साथ हमारी संस्थाओं के लिए इकाई ढांचे में "LIKE" ऑपरेटर को लागू करने की कोशिश कर रहे हैं, लेकिन यह समर्थित नहीं है। क्या किसी और ने ऐसा कुछ करने की कोशिश की है?

यह ब्लॉग पोस्ट उस समस्या को सारांशित करता है जो हम कर रहे हैं। हम उपयोग कर सकते हैं, लेकिन यह केवल LIKE के लिए सबसे तुच्छ मामले से मेल खाता है। संयोजन में, startswith, Endwith, और indexof शामिल हैं, जो हमें वहां मिलता है, लेकिन मानक वाइल्डकार्ड और Linq से Entities कोड के बीच अनुवाद की आवश्यकता होती है।


1
इस उत्तर पर जाएं यदि आप पहले से ही EF 6.2.x का उपयोग कर रहे हैं। करने के लिए इस सवाल का जवाब आप उपयोग कर रहे हैं, तो एफई कोर 2.x
CodeNotFound

जवाबों:


36

यह अब एक पुरानी पोस्ट है, लेकिन किसी को भी उत्तर की तलाश में, इस लिंक की मदद करनी चाहिए। इस उत्तर पर जाएं यदि आप पहले से ही EF 6.2.x का उपयोग कर रहे हैं। करने के लिए इस सवाल का जवाब आप एफई कोर 2.x उपयोग कर रहे हैं

लघु संस्करण:

SqlFunctions.PatIndex विधि - एक निर्दिष्ट अभिव्यक्ति में एक पैटर्न की पहली घटना की प्रारंभिक स्थिति लौटाता है, या यदि सभी मान्य पाठ और वर्ण डेटा प्रकारों पर पैटर्न नहीं मिला है, तो शून्य

नामस्थान: System.Data.Objects.SqlClient विधानसभा: System.Data.Entity (System.Data.Entity.dll में)

इस फोरम थ्रेड में थोड़ा सा स्पष्टीकरण भी दिखाई देता है ।


59
कैसे स्वीकार किया जाता है जो एक MSDN मंच से लिंक होता है जो नीचे दिए गए उत्तर के लिए इस प्रश्न से जोड़ता है ?
इयोनसदान

उत्तर SqlFunctions.PatIndex विधि का उपयोग करना था। लिंक किए गए फ़ोरम थ्रेड को थोड़ी अधिक "पृष्ठभूमि" जानकारी प्रदान करनी थी।
यन दुरान

नीचे दिए गए उत्तर सरल पैटर्न के लिए अच्छे हैं, लेकिन अगर मैं "WHERE Name LIKE 'abc [0-9]%'" या कुछ अन्य अधिक जटिल पैटर्न कहना चाहता हूं, तो बस कॉन्टेन्स () का उपयोग करना काफी कटौती नहीं करता है।
हॉटएन

1
इस सवाल का पुराना जवाब है। (इसके पहले भाग का नहीं, बल्कि इसके वैकल्पिक समाधान का।)
Frédéric

154

मैं वास्तव में EF के बारे में कुछ नहीं जानता, लेकिन LINQ से SQL में आप आमतौर पर String.Containes का उपयोग करके एक LIKE क्लॉज व्यक्त करते हैं:

where entity.Name.Contains("xyz")

में अनुवाद करता है

WHERE Name LIKE '%xyz%'

(प्रयोग StartsWithऔर EndsWithअन्य व्यवहार के लिए।)

मुझे पूरी तरह से यकीन नहीं है कि यह मददगार है, क्योंकि मुझे समझ में नहीं आता है कि जब आप कहते हैं कि आप LIKE को लागू करने की कोशिश कर रहे हैं । अगर मैं पूरी तरह से गलत समझा, मुझे पता है और मैं इस जवाब को हटा दूँगा :)


4
कृपया ध्यान दें कि "व्हेयर नेम लाइक '% xyz%'" एक इंडेक्स का उपयोग करने में असमर्थ होगा, इसलिए यदि टेबल बहुत बड़ा है तो वह अच्छा प्रदर्शन नहीं कर सकता है ...
मिच गेहूं

1
ठीक है, हम ब्ला * फू बार बार फू? बार? फू बार पर मिलान करने में सक्षम होना चाहते हैं ? और अन्य जटिल पैटर्न। हमारा वर्तमान दृष्टिकोण आपके द्वारा उल्लिखित के समान है, हम उन प्रश्नों को उन कार्यों में परिवर्तित कर देंगे जिनमें शामिल हैं, इंडेक्स, स्टार्टस्विथ, एंडस्विथ, इत्यादि। मैं उम्मीद कर रहा था कि एक अधिक सामान्य-उद्देश्य समाधान था।
ब्रायन

2
ऐसा नहीं है कि मुझे पता है - मुझे संदेह है कि जटिल पैटर्न अधिक डीबी-विशिष्ट होते हैं, और सामान्य तरीके से व्यक्त करने के लिए कठिन होते हैं।
जॉन स्कीट

4
@Jon Skeet: मेरे सर्वश्रेष्ठ ज्ञान के लिए LIKE कार्यक्षमता ANSI मानक में है और यह SQL सर्वर, Oracle, और DB2 में बहुत समान है।
एके

2
एक बात जो मैंने इन ऑपरेटरों और MS SQL का उपयोग करते हुए देखी है, वह यह है कि EF उन्हें बचाये गए मापदंडों के रूप में जोड़ता है "Name LIKE @ p__linq__1 ESCAPE N '~'" जो मेरे बहुत ही सीमित उपयोग के मामले में बहुत धीमी गति से प्रदर्शन करता है, यदि खोज स्ट्रिंग केवल क्वेरी में "नाम"% xyz% 'की तरह है। उन परिदृश्यों के लिए जिनके पास मैं अभी भी स्टार्टस्विथ और कॉन्टेन्स का उपयोग कर रहा हूं, लेकिन मैं इसे डायनामिक लाइन के माध्यम से करता हूं क्योंकि यह एसक्यूएल स्टेटमेंट में पैरामीटर को इंजेक्ट करता है जो मेरे परिदृश्य में उत्पादन कर रहा है अधिक कुशल क्वेरी। निश्चित नहीं है कि यह EF 4.0 है या नहीं। आप एक ही चीज़ को प्राप्त करने के लिए ObjectQueryParameters का भी उपयोग कर सकते हैं ...
शेन Neuville

35

मुझे भी यही समस्या थी।

अभी के लिए, मैंने http://www.codeproject.com/Articles/11556/Converting-Wildcards-to-Regexes?msg=1423024_xx1423024xxxx पर आधारित क्लाइंट-साइड वाइल्डकार्ड / रेगेक्स फ़िल्टरिंग के साथ समझौता किया है - यह सरल है और यह काम करता है। अपेक्षित होना।

मुझे इस विषय पर एक और चर्चा मिली है: http://forums.asp.net/t/1654093.aspx/2/10
यह पोस्ट आशाजनक लगता है यदि आप इकाई फ्रेमवर्क का उपयोग करते हैं> = 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);

नोट: यह समाधान केवल SQL- सर्वर के लिए है, क्योंकि यह गैर-मानक PATINDEX फ़ंक्शन का उपयोग करता है।


जबकि PatIndex "काम करता है", यह आपको काटने के लिए वापस आ जाएगा, PatIndex में जहां खंड उस स्तंभ पर अनुक्रमणिका का उपयोग नहीं करता है जिसे आप फ़िल्टर करना चाहते हैं।
ब्लैकिस

@BlackICE से यह उम्मीद है। जब आप आंतरिक पाठ (% CD% BLUE%) पर खोज करते हैं, तो सर्वर अनुक्रमित का उपयोग करने में सक्षम नहीं होगा। जब भी संभव हो, भीख मांगने (CD% BLUE%) से पाठ खोजना अधिक कुशल है।
प्रातः

@surfen patindex इससे भी बदतर है, हालांकि, यह सामने वाले% के बिना भी इंडेक्स का उपयोग नहीं करेगा, patindex के साथ खोज (BLUE CD%) कॉलम इंडेक्स का उपयोग नहीं करेगा।
ब्लैकिस

23

अपडेट: ईएफ 6.2 में एक ऑपरेटर की तरह है

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

क्या यह एक स्पष्ट उदाहरण नहीं होगा Where(obj => DbFunctions.Like(obj.Column , "%expression%"):?
DCD

यह निश्चित है। इसे बदला
Lode Vlaeminck

20

वहाँ है 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बजाय CHARINDEXहम Containsविधि के लिए देखते हैं ।


5

यह डॉक्यूमेंट में एंटिटी एसक्यूएल के हिस्से के रूप में विशेष रूप से उल्लेखित है। क्या आपको कोई त्रुटि संदेश मिल रहा है?

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


1
यदि आप भविष्य में EF से दूर जाना चाहते हैं तो मुझे Entity SQL से दूर रहने का प्रलोभन दिया जाएगा। इसके बजाय इसे सुरक्षित रखें और मूल प्रतिक्रिया में (), स्टार्टस्विथ () और एंड्सविथ () विकल्पों के साथ रहें।
स्टीफन न्यूमैन

1
यह ठीक संकलन करता है, लेकिन रनटाइम में विफल रहता है।
15

मेरे द्वारा पोस्ट किया गया कोड रनटाइम में विफल रहता है? यह Microsoft लिंक से आता है।
रॉबर्ट हार्वे

मैंने एक ब्लॉग पोस्ट के लिंक के साथ प्रश्न को उसी समस्या का वर्णन करते हुए संपादित किया है जो हमारे पास है।
रिश्वत दें

लगता है कि इसमें शामिल हैं () आपका टिकट है। लेकिन जैसा कि जॉन स्कीट ने बताया, आपको कुछ वास्तविक एसक्यूएल को सीधे डेटाबेस में हेरफेर करना पड़ सकता है, अगर इसमें आपकी जरूरतें पूरी नहीं होती हैं।
रॉबर्ट हार्वे

2

यदि आप MS Sql का उपयोग कर रहे हैं, तो मैंने वाइल्डकार्ड खोज के लिए% वर्ण का समर्थन करने के लिए 2 विस्तार विधियाँ लिखी हैं। (LinKKit की आवश्यकता है)

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

एफई 6 में और इसका अनुवाद करना चाहिए

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


आपकी टिप्पणी के लिए धन्यवाद Ronel, वहाँ कुछ भी मैं मदद कर सकता है? त्रुटि संदेश क्या है?
स्टीवन चोंग

2

EfCore के लिए यहाँ LIKE एक्सप्रेशन बनाने के लिए एक नमूना है

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

0

आप लिंक की तरह एक वास्तविक का उपयोग कर सकते हैं काफी आसानी से

जोड़ना

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

इस टैग में अपने EDMX के लिए:

edmx: edmx / edmx: रनटाइम / edmx: ConceptualModels / स्कीमा

नामस्थान भी याद रखें <schema namespace="" />विशेषता

फिर उपरोक्त नामस्थान में एक विस्तार वर्ग जोड़ें:

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

यह एक्सटेंशन विधि अब EDMX फ़ंक्शन पर मैप करेगी।

अधिक जानकारी यहाँ: http://jendaperl.blogspot.be/2011/02/like-in-linq-to-entities.html

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