LINQ अभिव्यक्ति में String.IsNullOrWhiteSpace


151

मेरे पास निम्नलिखित कोड हैं:

return this.ObjectContext.BranchCostDetails.Where(
    b => b.TarrifId == tariffId && b.Diameter == diameter
        || (b.TarrifId==tariffId && !string.IsNullOrWhiteSpace(b.Diameter))
        || (!b.TarrifId.HasValue) && b.Diameter==diameter);

और मुझे यह त्रुटि तब मिलती है जब मैं कोड चलाने की कोशिश करता हूं:

LINQ to Entities विधि 'बूलियन IsNullOrWhiteSpace (System.String)' विधि को मान्यता नहीं देता है, और इस पद्धति का स्टोर अभिव्यक्ति में अनुवाद नहीं किया जा सकता है। "

मैं इस समस्या को कैसे हल कर सकता हूं और इससे बेहतर कोड लिख सकता हूं?

जवाबों:


263

आपको प्रतिस्थापित करने की आवश्यकता है

!string.IsNullOrWhiteSpace(b.Diameter)

साथ में

!(b.Diameter == null || b.Diameter.Trim() == string.Empty)

Linq से संस्थाओं के लिए इसका अनुवाद किया जाता है:

DECLARE @p0 VarChar(1000) = ''
...
WHERE NOT (([t0].[Diameter] IS NULL) OR (LTRIM(RTRIM([t0].[Diameter])) = @p0))

और एसक्यूएल के लिए लाइनक के लिए लेकिन लगभग समान नहीं है

DECLARE @p0 NVarChar(1000) = ''
...
WHERE NOT (LTRIM(RTRIM([t0].[TypeName])) = @p0)

3
क्यों? यह कोड संकलित करता है:List<string> my = new List<string>(); var i = from m in my where !string.IsNullOrWhiteSpace(m) select m;
एरिक जे।

37
यह संकलित हो सकता है, लेकिन यह SQL में Linq द्वारा संस्थाओं में अनुवादित नहीं किया जाएगा। विधि 'बूलियन IsNullOrWhiteSpace (System.String)' का SQL में कोई समर्थित अनुवाद नहीं है। वही IsNullOrEmpty के लिए लागू होता है।
फिल

1
लिनिक से एसक्यूएल के लिए यही सच है
फिल

3
सतर्कता का एक शब्द: "string.Empty 'को" "(उर्फ खाली स्ट्रिंग) पर नियोजित करना सबसे महत्वपूर्ण है। पूर्व काम करता है बाद वाला नहीं (कम से कम जहाँ तक ओरेकल के ईएफ ड्राइवर का संबंध है)। यदि आप उपयोग करते हैं तो आका: b.Diameter.Trim () == "" <- यह इरादा के अनुसार काम नहीं करेगा (पागल मुझे पता है ...)
XDS

ऐसा लगता है कि ट्रिम () भी MongoDB.Driver का उपयोग करके कम से कम प्रश्नों के लिए समर्थित नहीं है
Leandro hereñu

20

इस मामले में IQueryable<T>और के बीच अंतर करना महत्वपूर्ण है IEnumerable<T>। संक्षेप IQueryable<T>में एक LINQ प्रदाता द्वारा एक अनुकूलित क्वेरी देने के लिए संसाधित किया जाता है। इस परिवर्तन के दौरान सभी C # कथनों का समर्थन नहीं किया जाता है, क्योंकि या तो उन्हें बैक-एंड विशिष्ट क्वेरी (जैसे SQL) में अनुवाद करना संभव नहीं है या क्योंकि कार्यान्वयनकर्ता ने कथन की आवश्यकता का पूर्वाभास नहीं किया है।

इसके विपरीत IEnumerable<T>ठोस वस्तुओं के खिलाफ निष्पादित किया जाता है और इसलिए, रूपांतरित नहीं किया जाएगा। इसलिए, यह काफी सामान्य है कि निर्माण, जो प्रयोग करने योग्य हैं IEnumerable<T>, के साथ उपयोग नहीं किया जा सकता है IQueryable<T>और यह भी कि IQueryables<T>विभिन्न LINQ प्रदाताओं द्वारा समर्थित कार्यों के एक ही सेट का समर्थन नहीं करते हैं।

हालाँकि, कुछ वर्कअराउंड्स हैं (जैसे फिल का उत्तर ), जो क्वेरी को संशोधित करता है। इसके अलावा, एक अधिक सामान्य दृष्टिकोण IEnumerable<T>के रूप में क्वेरी के विनिर्देश के साथ जारी रखने से पहले वापस छोड़ना संभव है । यह, हालांकि, एक प्रदर्शन हिट हो सकता है - विशेष रूप से प्रतिबंधों पर इसका उपयोग करते समय (जैसे जहां खंड)। इसके विपरीत, जब परिवर्तनों से निपटने के लिए प्रदर्शन हिट बहुत छोटा होता है, तो कभी-कभी गैर-मौजूद भी होता है - आपकी क्वेरी के आधार पर।

तो उपरोक्त कोड भी इस तरह से फिर से लिखा जा सकता है:

return this.ObjectContext.BranchCostDetails
    .AsEnumerable()
    .Where(
        b => b.TarrifId == tariffId && b.Diameter == diameter
        || (b.TarrifId==tariffId && !string.IsNullOrWhiteSpace(b.Diameter))
        ||(!b.TarrifId.HasValue) && b.Diameter==diameter
    );

नोट: Ths कोड पर Phil के उत्तर की तुलना में उच्च प्रदर्शन प्रभाव पड़ेगा । हालाँकि, यह सिद्धांत को दर्शाता है।


10

String.IsNullOrWhiteSpace के संदर्भों का पता लगाने के लिए एक अभिव्यक्ति आगंतुक का उपयोग करें और उन्हें एक सरल अभिव्यक्ति में तोड़ दें (x == null || x.Trim() == string.Empty)

तो नीचे एक विस्तारित आगंतुक और इसका उपयोग करने के लिए एक विस्तार विधि है। इसका उपयोग करने के लिए किसी विशेष कॉन्फिग की आवश्यकता नहीं है, बस कहां के बजाय कहां से कॉल करें।

public class QueryVisitor: ExpressionVisitor
{
    protected override Expression VisitMethodCall(MethodCallExpression node)
    {
        if (node.Method.IsStatic && node.Method.Name == "IsNullOrWhiteSpace" && node.Method.DeclaringType.IsAssignableFrom(typeof(string)))
        {
            //!(b.Diameter == null || b.Diameter.Trim() == string.Empty)
            var arg = node.Arguments[0];
            var argTrim = Expression.Call(arg, typeof (string).GetMethod("Trim", Type.EmptyTypes));

            var exp = Expression.MakeBinary(ExpressionType.Or,
                    Expression.MakeBinary(ExpressionType.Equal, arg, Expression.Constant(null, arg.Type)),
                    Expression.MakeBinary(ExpressionType.Equal, argTrim, Expression.Constant(string.Empty, arg.Type))
                );

            return exp;
        }

        return base.VisitMethodCall(node);
    }
}

public static class EfQueryableExtensions
{
    public static IQueryable<T> WhereEx<T>(this IQueryable<T> queryable, Expression<Func<T, bool>> where)
    {
        var visitor = new QueryVisitor();
        return queryable.Where(visitor.VisitAndConvert(where, "WhereEx"));
    }
}

इसलिए यदि आप myqueryable.WhereEx(c=> !c.Name.IsNullOrWhiteSpace())इसे चलाते हैं, तो इसे !(c.Name == null || x.Trim() == "")जो कुछ भी पास किया जा रहा है, उससे पहले परिवर्तित किया जाएगा (sql / संस्थाओं के लिए) और sql में परिवर्तित किया जाएगा।


ऐसी सरल आवश्यकता के लिए फिल के उत्तर की तुलना में बहुत अधिक जटिल, लेकिन अभिव्यक्तिविवादक के बारे में शैक्षिक उद्देश्य के लिए बहुत दिलचस्प है, धन्यवाद
संक्षिप्त करें

2

आप इसका उपयोग व्हॉट्सएप की जांच के लिए भी कर सकते हैं:

b.Diameter!=null && !String.IsNullOrEmpty(b.Diameter.Trim())

6
यदि व्यास शून्य है, तो यह एक अपवाद फेंक देगा।
ओकेन कोकिजीत

@OkanKocyigit आप सही हैं। मैंने उत्तर संपादित किया है। :)
माजिद २

0
!String.IsNullOrEmpty(b.Diameter.Trim()) 

अगर b.Diameterहै तो अपवाद फेंक देंगे null
यदि आप अभी भी अपने बयान का उपयोग करना चाहते हैं, तो इस चेक का बेहतर उपयोग करें

!String.IsNullOrWhiteSpace(b.Diameter), IsNullOrWhiteSpace = IsNullOrEmpty + WhiteSpace

2
StackOverflow में आपका स्वागत है! सबसे पहले, एसओ पर एक उत्तरदाता के रूप में भाग लेने के लिए धन्यवाद। कृपया एक स्पष्ट और आसान उत्तर बनाने के लिए प्रारूपण पर एक नज़र डालें ।
हिले
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.