Linq Entities तक - SQL "IN" खंड


230

T-SQL में आपके पास एक क्वेरी हो सकती है जैसे:

SELECT * FROM Users WHERE User_Rights IN ("Admin", "User", "Limited")

आप LINQ में Entities क्वेरी के लिए कैसे दोहराएंगे? क्या यह भी संभव है?

जवाबों:


349

जिस तरह से आप इसके बारे में सोच रहे हैं, उसके संदर्भ में आपको इसे अपने सिर पर बदलना होगा। लागू उपयोगकर्ता अधिकारों के पूर्वनिर्धारित सेट में वर्तमान आइटम के उपयोगकर्ता अधिकारों को खोजने के लिए "इन" करने के बजाय, यदि आप वर्तमान आइटम के लागू मूल्य को शामिल करते हैं, तो आप उपयोगकर्ता अधिकारों का एक पूर्वनिर्धारित सेट पूछ रहे हैं। यह ठीक उसी तरह है जैसे आप एक आइटम को नियमित सूची में .NET में पाते हैं।

LINQ का उपयोग करने के दो तरीके हैं, एक क्वेरी सिंटैक्स का उपयोग करता है और दूसरा सिंटैक्स सिंटैक्स का उपयोग करता है। अनिवार्य रूप से, वे समान हैं और आपकी पसंद के आधार पर परस्पर उपयोग किया जा सकता है:

क्वेरी सिंटैक्स:

var selected = from u in users
               where new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights)
               select u

foreach(user u in selected)
{
    //Do your stuff on each selected user;
}

विधि सिंटैक्स:

var selected = users.Where(u => new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights));

foreach(user u in selected)
{
    //Do stuff on each selected user;
}

इस उदाहरण में मेरी व्यक्तिगत पसंद विधि वाक्यविन्यास हो सकती है क्योंकि चर को निर्दिष्ट करने के बजाय, मैं इस तरह से एक अनाम कॉल पर फॉर्च्यूस कर सकता हूं:

foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
    //Do stuff on each selected user;
}

सिंथेटिक रूप से यह अधिक जटिल लगता है, और आपको लैम्ब्डा एक्सप्रेशन या डेलिगेट्स की अवधारणा को समझना होगा कि वास्तव में क्या चल रहा है, लेकिन यह आप देख सकते हैं, यह कोड को एक उचित राशि देता है।

यह सब आपकी कोडिंग शैली और पसंद पर निर्भर करता है - मेरे तीनों उदाहरण एक ही काम को थोड़ा अलग तरीके से करते हैं।

एक वैकल्पिक तरीका भी LINQ का उपयोग नहीं करता है, आप "FindAll" के साथ "जहाँ" की समान विधि सिंटैक्स का उपयोग कर सकते हैं और वही परिणाम प्राप्त कर सकते हैं, जो .NET 2.0 में भी काम करेगा:

foreach(User u in users.FindAll(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
    //Do stuff on each selected user;
}

शायद मुझे जवाब के रूप में चिह्नित करने की बहुत जल्दी थी, लेकिन मुझे {"व्यवस्थापक", "उपयोगकर्ता", "सीमित"} VS2008 के बाद एक कोड नहीं मिला। VS2008 को यह कोड एक सा पसंद नहीं है।
स्टीवनएमसीड

1
मेरे नाम "FailBoy" के लिए सच है मैंने यह पता लगाया: PI एक स्ट्रिंग में डाल दिया [] और फिर इसका इस्तेमाल किया और यह काम किया। धन्यवाद!
स्टीवनएमसीड

क्षमा करें, मैं अनाम सरणी को नया बनाना भूल गया;) मैंने अपना कोड उदाहरण तय किया। खुशी है कि आप इसे अपने दम पर समझ गए।
बेनलास्टर

28
यह उत्तर सही था कि प्रश्न सामान्य रूप से Linq-to-SQL या Linq के बारे में था। हालांकि, चूंकि यह विशेष रूप से "लिनक-टू-एंटिटीज" कहता है, इसलिए यह उत्तर गलत है। array.Ctaintains Linq-to-Entities द्वारा समर्थित (अभी तक) नहीं है।
क्रिस्टोफर

6
@ क्रिस्तोफर - यह EF के पुराने संस्करणों के लिए सच हो सकता है, लेकिन यह EF4 के साथ मेरे लिए ठीक लगता है।
ड्रू नोक

21

इससे आपका उद्देश्य पूरा होना चाहिए। यह दो संग्रहों की तुलना करता है और जाँचता है कि क्या एक संग्रह में दूसरे संग्रह में मिलान करने वाले मूल्य हैं

fea_Features.Where(s => selectedFeatures.Contains(s.feaId))

9

यदि आप VS2008 / .net 3.5 का उपयोग कर रहे हैं, तो एलेक्स जेम्स की टिप # 8 देखें: http://blogs.msdn.com/alexj/archive/2009/03/26/tip-8-writing-where-in-style -queries-का उपयोग कर-LINQ करने वाली entities.aspx

अन्यथा केवल array.Ctaintains (someEntity.Member) विधि का उपयोग करें।


कृपया लिंक-ओनली उत्तर का उपयोग करने से बचें, आपको भविष्य में लिंक के टूटने की स्थिति में, अपने उत्तर में लिंक की सामग्री को संक्षेप में प्रस्तुत करना चाहिए।


8

मैं इस संदर्भ में इनर जॉइन के लिए जाऊंगा। अगर मेरा उपयोग होता, तो यह 6 बार होता, बावजूद इसके कि सिर्फ एक मैच होता।

var desiredNames = new[] { "Pankaj", "Garg" }; 

var people = new[]  
{  
    new { FirstName="Pankaj", Surname="Garg" },  
    new { FirstName="Marc", Surname="Gravell" },  
    new { FirstName="Jeff", Surname="Atwood" }  
}; 

var records = (from p in people join filtered in desiredNames on p.FirstName equals filtered  select p.FirstName).ToList(); 

इसमें नुकसान होता है

मान लीजिए मेरे पास दो सूची ऑब्जेक्ट हैं।

List 1      List 2
  1           12
  2            7
  3            8
  4           98
  5            9
  6           10
  7            6

युक्तियों का उपयोग करते हुए, यह सूची 2 में प्रत्येक सूची 1 आइटम के लिए खोज करेगा इसका मतलब है कि पुनरावृत्ति 49 बार होगी !!!


5
यह इस तथ्य को पूरी तरह से अनदेखा करता है कि कथन एसक्यूएल में अनुवादित है। देखें यहाँ
गर्ट अर्नोल्ड

5

यह संभव तरीका हो सकता है जिसमें आप सीधे खंड में जाँच करने के लिए LINQ एक्सटेंशन विधियों का उपयोग कर सकते हैं

var result = _db.Companies.Where(c => _db.CurrentSessionVariableDetails.Select(s => s.CompanyId).Contains(c.Id)).ToList();

2

मैंने SQL-IN जैसी चीज़ के साथ काम करने की भी कोशिश की - एक इकाई डेटा मॉडल के खिलाफ क्वेरी । मेरा दृष्टिकोण एक बड़े OR-अभिव्यक्ति की रचना करने के लिए एक स्ट्रिंग बिल्डर है। यह बहुत बदसूरत है, लेकिन मुझे डर है कि यह अभी जाने का एकमात्र तरीका है।

अब ठीक है, इस तरह दिखता है:

Queue<Guid> productIds = new Queue<Guid>(Products.Select(p => p.Key));
if(productIds.Count > 0)
{
    StringBuilder sb = new StringBuilder();
    sb.AppendFormat("{0}.ProductId = Guid\'{1}\'", entities.Products.Name, productIds.Dequeue());
    while(productIds.Count > 0)
    {
        sb.AppendFormat(" OR {0}.ProductId = Guid\'{1}\'",
          entities.Products.Name, productIds.Dequeue());
    }
}

इस संदर्भ में GUID के साथ कार्य करना : जैसा कि आप ऊपर देख सकते हैं, हमेशा GUID से पहले "GUID" शब्द होता है यदि क्वेरी स्ट्रिंग टुकड़ों में स्वयं। यदि आप इसे नहीं जोड़ते हैं, ObjectQuery<T>.Whereतो निम्न अपवाद फेंकता है:

इस ऑपरेशन के लिए तर्क प्रकार 'Edm.Guid' और 'Edm.String' असंगत हैं, अभिव्यक्ति के पास, लाइन 6, कॉलम 14।

एमएसडीएन फ़ोरम में यह पाया गया, मन में उपयोगी हो सकता है।

मथायस

... .NET और एंटिटी फ्रेमवर्क के अगले संस्करण की प्रतीक्षा कर रहा है, जब सब कुछ बेहतर हो जाए। :)


2

बेनालास्टर जवाब के लिए एक वैकल्पिक विधि

सबसे पहले, आप इस तरह से क्वेरी को फिर से लिख सकते हैं:

var matches = from Users in people
        where Users.User_Rights == "Admin" ||
              Users.User_Rights == "Users" || 
              Users.User_Rights == "Limited"
        select Users;

निश्चित रूप से यह अधिक 'चिंताजनक' और लिखने के लिए एक दर्द है, लेकिन यह सभी समान काम करता है।

इसलिए यदि हमारे पास कुछ उपयोगिता पद्धति है, जिससे इस प्रकार के LINQ अभिव्यक्तियाँ बनाना आसान हो जाता है, तो हम व्यवसाय में होंगे।

एक उपयोगिता विधि के साथ आप इस तरह से कुछ लिख सकते हैं:

var matches = ctx.People.Where(
        BuildOrExpression<People, string>(
           p => p.User_Rights, names
        )
);

यह एक अभिव्यक्ति का निर्माण करता है जिसका प्रभाव उसी प्रकार है:

var matches = from p in ctx.People
        where names.Contains(p.User_Rights)
        select p;

लेकिन जो अधिक महत्वपूर्ण वास्तव में .NET 3.5 SP1 के खिलाफ काम करता है।

यहाँ प्लंबिंग फंक्शन है जो इसे संभव बनाता है:

public static Expression<Func<TElement, bool>> BuildOrExpression<TElement, TValue>(
        Expression<Func<TElement, TValue>> valueSelector, 
        IEnumerable<TValue> values
    )
{     
    if (null == valueSelector) 
        throw new ArgumentNullException("valueSelector");

    if (null == values)
        throw new ArgumentNullException("values");  

    ParameterExpression p = valueSelector.Parameters.Single();

    if (!values.Any())   
        return e => false;

    var equals = values.Select(value =>
        (Expression)Expression.Equal(
             valueSelector.Body,
             Expression.Constant(
                 value,
                 typeof(TValue)
             )
        )
    );
   var body = equals.Aggregate<Expression>(
            (accumulate, equal) => Expression.Or(accumulate, equal)
    ); 

   return Expression.Lambda<Func<TElement, bool>>(body, p);
}

मैं इस पद्धति की व्याख्या करने की कोशिश नहीं कर रहा हूं, यह कहने के अलावा कि यह अनिवार्य रूप से मान का उपयोग कर सभी मूल्यों के लिए एक विधेय अभिव्यक्ति का निर्माण करता है (यानी p => p.User_Rights) और उन लोगों को एक साथ पूर्ण के लिए एक अभिव्यक्ति बनाने के लिए भविष्यवाणी करता है। विधेय

स्रोत: http://blogs.msdn.com/b/alexj/archive/2009/03/26/tip-8-writing-where-in-style-queries-using-linq-to-entities.aspx


0

वास्तविक उदाहरण:

var trackList = Model.TrackingHistory.GroupBy(x => x.ShipmentStatusId).Select(x => x.Last()).Reverse();
List<int> done_step1 = new List<int>() {2,3,4,5,6,7,8,9,10,11,14,18,21,22,23,24,25,26 };
bool isExists = trackList.Where(x => done_step1.Contains(x.ShipmentStatusId.Value)).FirstOrDefault() != null;

-13

गंभीरता से? आप लोगों ने कभी इस्तेमाल नहीं किया

where (t.MyTableId == 1 || t.MyTableId == 2 || t.MyTableId == 3)

9
-1, 1000 से अधिक पंक्तियों वाली तालिका में 20 या अधिक मानों के साथ इसे आज़माएं और आपको स्वीकृत समाधान का लाभ जल्दी से दिखाई देगा। साथ ही, जहां कथन (जैसे कि उपयोगकर्ता विकल्प 1 और 2 को शामिल करने के लिए चयन कर रहा है, लेकिन 3 नहीं) के लिए मनमानी संख्या को जोड़ना आसान नहीं है।
त्रिशूल

खैर, मुझे किसी पागल वैज्ञानिक सामान की आवश्यकता नहीं थी और इस जवाब ने मेरा मत जाना क्योंकि मुझे AND और 2 ORS var SamplePoints = (c से _db.tblPWS_WSF_SPID_ISN_Lookup.OderderBy (x => x.WSFStateCode) की आवश्यकता थी जहाँ c। PWS == आईडी && ((c.WSFStateCode.Substring (0, 2) == "SR") || (c.WSFStateCode.Substring (0, 2) == "CH") चयन c) .ToList () || ;
JustJohn

@ छंटनी - पंक्तियों की संख्या (1000) कुछ भी नहीं बदलती - या क्या मुझे कुछ याद नहीं है?
22

@ जिमस्की हाँ, पंक्तियों की संख्या। जितनी अधिक पंक्तियाँ, उतनी गणनाएँ। संभव मूल्यों की संख्या के साथ भी Checks = NumValues * NumRows:। क्योंकि यह एक M * N प्रकार की गणना है, यदि या तो छोटा है तो प्रत्येक आवश्यक जांच करने का समय भी छोटा होगा। मैंने कसना जोड़ा इसलिए cjm30305 को पता चल जाएगा कि एक परीक्षण वातावरण कैसे स्थापित किया जाए, जहां यह दिखाया जाए कि उसका समाधान खराब क्यों है।
१।

@ क्रिसित क्या आप कह रहे हैं कि where new[] { 1, 2, 3 }.Contains(x)कम तुलना करता है फिर where (x == 1 || x == 2 || x == 3)?
tymtam
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.