सशर्त Linq क्वेरी


92

हम एक लॉग व्यूअर पर काम कर रहे हैं। उपयोग में उपयोगकर्ता द्वारा फ़िल्टर करने का विकल्प होगा, गंभीरता, आदि। Sql दिनों में मैं क्वेरी स्ट्रिंग में जोड़ दूंगा, लेकिन मैं इसे Linq के साथ करना चाहता हूं। मैं सशर्त रूप से कहां-कहां खंड जोड़ सकता हूं?

जवाबों:


156

यदि आप केवल फ़िल्टर करना चाहते हैं यदि कुछ मानदंड पारित किए जाते हैं, तो ऐसा कुछ करें

var logs = from log in context.Logs
           select log;

if (filterBySeverity)
    logs = logs.Where(p => p.Severity == severity);

if (filterByUser)
    logs = logs.Where(p => p.User == user);

इस तरह से करने से आपके एक्सप्रेशन ट्री को वैसा ही होने दिया जाएगा जैसा आप चाहते हैं। इस तरह से बनाई गई एसक्यूएल ठीक वही होगी जो आपको चाहिए और कुछ भी कम नहीं।


2
नमस्ते क्या आपके पास कोई आदेश है कि कहां और उसके बजाय ORS ..?
जॉन एच।

1
हाँ ... यह करना थोड़ा कठिन है। मैंने जो सबसे अच्छा देखा है वह विनिर्देशन पैटर्न के माध्यम से है और विनिर्देश में विधेय को खींच रहा है और फिर विनिर्देशन कह रहा है। (someOtherSpidification)। मूल रूप से आपको अपनी अभिव्यक्ति का पेड़ थोड़ा लिखना होगा। उदाहरण कोड और स्पष्टीकरण यहाँ: codeinsanity.com/archive/2008/08/13/…
डेरेन कोप्प

मेरे पास एक बेवकूफ सवाल है, अगर ये लॉग डेटाबेस से प्राप्त किए जा रहे हैं, तो क्या हम सभी लॉग प्राप्त कर रहे हैं और फिर उन्हें मेमोरी में फ़िल्टर कर रहे हैं? यदि ऐसा है तो मैं कैसे डेटाबेस को शर्तों को पारित कर सकता हूं
अली उमैर

यह उन्हें स्मृति में फ़िल्टर नहीं कर रहा है। यह एक क्वेरी बना रहा है और डेटाबेस में सभी शर्तों को भेज रहा है (कम से कम अधिकांश लाइन-टू-एक्स प्रदाताओं के लिए)
डैरेन कोप्प

यह त्रुटि हो रही हैLINQ to Entities does not recognize the method 'System.String get_Item(System.String)' method, and this method cannot be translated into a store expression.
अली उमैर

22

यदि आपको सूची / आधार पर आधार को फ़िल्टर करने की आवश्यकता है, तो निम्नलिखित का उपयोग करें:

    public List<Data> GetData(List<string> Numbers, List<string> Letters)
    {
        if (Numbers == null)
            Numbers = new List<string>();

        if (Letters == null)
            Letters = new List<string>();

        var q = from d in database.table
                where (Numbers.Count == 0 || Numbers.Contains(d.Number))
                where (Letters.Count == 0 || Letters.Contains(d.Letter))
                select new Data
                {
                    Number = d.Number,
                    Letter = d.Letter,
                };
        return q.ToList();

    }

3
यह अब तक का सबसे अच्छा और सबसे सही उत्तर है। सशर्त || केवल पहले भाग की तुलना करता है और दूसरे भाग को छोड़ता है यदि पहला भाग सत्य है ... अच्छा किया!
सर्ज सगन

1
इस निर्माण में उत्पन्न SQL क्वेरी में अभिव्यक्ति का 'या' हिस्सा शामिल है। स्वीकृत उत्तर अधिक कुशल कथन उत्पन्न करेगा। डेटा प्रदाता के अनुकूलन पर निर्भर करता है, निश्चित रूप से। LINQ-to-SQL में बेहतर अनुकूलन हो सकता है, लेकिन LINQ-to-Entities नहीं है।
सनकैट २२

20

मैंने डैरन के समान उत्तर का उपयोग करके समाप्त कर दिया, लेकिन एक IQueryable इंटरफ़ेस के साथ:

IQueryable<Log> matches = m_Locator.Logs;

// Users filter
if (usersFilter)
    matches = matches.Where(l => l.UserName == comboBoxUsers.Text);

 // Severity filter
 if (severityFilter)
     matches = matches.Where(l => l.Severity == comboBoxSeverity.Text);

 Logs = (from log in matches
         orderby log.EventTime descending
         select log).ToList();

डेटाबेस मारने से पहले क्वेरी बनाता है। कमांड अंत तक नहीं चलेगी .ToList () अंत में।


14

जब यह सशर्त लाइनक की बात आती है, तो मैं फिल्टर और पाइप पैटर्न के बहुत शौकीन हूं।
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/

मूल रूप से आप प्रत्येक फ़िल्टर केस के लिए एक एक्सटेंशन विधि बनाते हैं जो IQueryable और एक पैरामीटर में होती है।

public static IQueryable<Type> HasID(this IQueryable<Type> query, long? id)
{
    return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query;
}

8

LINQ को धाराप्रवाह अभिव्यक्ति के बीच सशर्त रूप से सक्षम करने की अनुमति देने के लिए मैंने इसे एक एक्सटेंशन विधि के साथ हल किया। यह ifबयानों के साथ अभिव्यक्ति को तोड़ने की आवश्यकता को दूर करता है ।

.If() विस्तार विधि:

public static IQueryable<TSource> If<TSource>(
        this IQueryable<TSource> source,
        bool condition,
        Func<IQueryable<TSource>, IQueryable<TSource>> branch)
    {
        return condition ? branch(source) : source;
    }

यह आपको ऐसा करने की अनुमति देता है:

return context.Logs
     .If(filterBySeverity, q => q.Where(p => p.Severity == severity))
     .If(filterByUser, q => q.Where(p => p.User == user))
     .ToList();

यहां एक IEnumerable<T>संस्करण भी है जो अधिकांश अन्य LINQ अभिव्यक्तियों को संभालेगा:

public static IEnumerable<TSource> If<TSource>(
    this IEnumerable<TSource> source,
    bool condition,
    Func<IEnumerable<TSource>, IEnumerable<TSource>> branch)
    {
        return condition ? branch(source) : source;
    }

4

एक और विकल्प यहाँ पर चर्चा की गई PredicateBuilder की तरह कुछ का उपयोग करना होगा । यह आपको निम्नलिखित की तरह कोड लिखने की अनुमति देता है:

var newKids  = Product.ContainsInDescription ("BlackBerry", "iPhone");

var classics = Product.ContainsInDescription ("Nokia", "Ericsson")
                  .And (Product.IsSelling());

var query = from p in Data.Products.Where (newKids.Or (classics))
            select p;

ध्यान दें कि मुझे केवल यह Linq 2 SQL के साथ काम करने के लिए मिला है। EntityFramework एक्सप्रेशन को लागू नहीं करता है। इंवोक, जो इस विधि को काम करने के लिए आवश्यक है। मेरे पास इस मुद्दे के बारे में एक सवाल है


डेटा ट्रांसफर ऑब्जेक्ट्स और Entity मॉडल के बीच मैप करने के लिए AutoMapper जैसे टूल के साथ अपनी रिपॉजिटरी के शीर्ष पर एक बिजनेस लॉजिक लेयर का उपयोग करने वालों के लिए यह एक शानदार तरीका है। विधेय बिल्डर का उपयोग करने से आपको स्वतः IMable को संशोधित करने की अनुमति मिल जाएगी, क्योंकि यह फ़्लैटनिंग के लिए ऑटोमैपर को भेजने से पहले यानी सूची को मेमोरी में लाना। ध्यान दें कि यह एंटिटी फ्रेमवर्क का भी समर्थन करता है।
चेरजशर्म

3

यह कर रहा हूं:

bool lastNameSearch = true/false; // depending if they want to search by last name,

इस whereकथन में:

where (lastNameSearch && name.LastNameSearch == "smith")

अर्थ यह है कि जब अंतिम क्वेरी बनाई गई है, अगर lastNameSearchहै falseक्वेरी पूरी तरह से अंतिम नाम खोज के लिए कोई SQL छोड़ देगा।


डेटा प्रदाता पर निर्भर करता है। LINQ-to-Entities यह अच्छी तरह से अनुकूलन नहीं करता है।
सनकैट २२

1

यह सबसे सुंदर बात नहीं है, लेकिन आप एक लंबोदर अभिव्यक्ति का उपयोग कर सकते हैं और वैकल्पिक रूप से अपनी शर्तों को पारित कर सकते हैं। TSQL में मैं मापदंडों को वैकल्पिक बनाने के लिए बहुत कुछ करता हूं:

कहाँ फ़ील्ड = @ फ़ीडलवर या @ फ़िल्डवर NULL है

आप निम्न लैम्ब्डा के साथ एक ही शैली की नकल कर सकते हैं (प्रमाणीकरण की जाँच का एक उदाहरण):

MyDataContext db = new MyDataContext ();

शून्य RunQuery (स्ट्रिंग param1, स्ट्रिंग param2, int; param3) {

फ़ंक चेकयूज़र = उपयोगकर्ता =>

((param1.Length> 0)? user.Param1 == param1: 1 == 1) &&

((param2.Length> 0)? user.Param2 == param2: 1 == 1) &&

((param3! = null); user.Param3 == param3: 1 == 1);

उपयोगकर्ता फाउंडर = db.Users.SingleOrDefault (चेकयूज़र);

}


1

मुझे हाल ही में इसी तरह की आवश्यकता थी और अंततः उसने एमएसडीएन में यह पाया। दृश्य स्टूडियो 2008 के लिए CSharp नमूने

डाउनलोड के डायनेमिक® नमूने में शामिल कक्षाएं आपको निम्नलिखित प्रारूप में रनटाइम पर गतिशील प्रश्न बनाने की अनुमति देती हैं:

var query =
db.Customers.
Where("City = @0 and Orders.Count >= @1", "London", 10).
OrderBy("CompanyName").
Select("new(CompanyName as Name, Phone)");

इसका उपयोग करके आप रनटाइम पर एक क्वेरी स्ट्रिंग को गतिशील रूप से बना सकते हैं और इसे कहां () विधि में पास कर सकते हैं:

string dynamicQueryString = "City = \"London\" and Order.Count >= 10"; 
var q = from c in db.Customers.Where(queryString, null)
        orderby c.CompanyName
        select c;

1

आप इस एक्सटेंशन विधि को बना और उपयोग कर सकते हैं

public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool isToExecute, Expression<Func<TSource, bool>> predicate)
{
    return isToExecute ? source.Where(predicate) : source;
}

0

बस C # का && ऑपरेटर का उपयोग करें:

var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")

संपादित करें: आह, और अधिक ध्यान से पढ़ने की जरूरत है। आप जानना चाहते थे कि सशर्त रूप से अतिरिक्त क्लॉस कैसे जोड़े जाएँ। उस मामले में, मुझे कोई पता नहीं है। :) मैं जो कर सकता हूं वह सिर्फ कई प्रश्नों को तैयार करना है, और सही एक को निष्पादित करना है, जो मुझे ज़रूरत है उसके आधार पर।


0

आप एक बाहरी विधि का उपयोग कर सकते हैं:

var results =
    from rec in GetSomeRecs()
    where ConditionalCheck(rec)
    select rec;

...

bool ConditionalCheck( typeofRec input ) {
    ...
}

यह काम करेगा, लेकिन अभिव्यक्ति के पेड़ में नहीं तोड़ा जा सकता है, जिसका अर्थ है कि लाइनक टू SQL हर रिकॉर्ड के खिलाफ चेक कोड चलाएगा।

वैकल्पिक रूप से:

var results =
    from rec in GetSomeRecs()
    where 
        (!filterBySeverity || rec.Severity == severity) &&
        (!filterByUser|| rec.User == user)
    select rec;

यह अभिव्यक्ति के पेड़ों में काम कर सकता है, जिसका अर्थ है कि लिनक्यू टू एसक्यूएल को अनुकूलित किया जाएगा।


0

खैर, जो मैंने सोचा था कि आप फ़िल्टर शर्तों को Predicates की एक सामान्य सूची में डाल सकते हैं:

    var list = new List<string> { "me", "you", "meyou", "mow" };

    var predicates = new List<Predicate<string>>();

    predicates.Add(i => i.Contains("me"));
    predicates.Add(i => i.EndsWith("w"));

    var results = new List<string>();

    foreach (var p in predicates)
        results.AddRange(from i in list where p.Invoke(i) select i);               

इस सूची में "me", "meyou", और "mow" शामिल हैं।

आप यह भविष्यवाणी कर सकते हैं कि एक पूरी तरह से अलग कार्य में भविष्यवाणी के साथ फोरकास्ट करने से ओआरएस सभी भविष्यवाणी करता है।

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