Id of linq के साथ सूची के आधार पर कई रिकॉर्ड का चयन करें


122

मेरे पास मेरी UserProfileतालिका की एक सूची है । मैं UserProfilesएक varप्रयोग में प्राप्त आईडी की सूची के आधार पर सभी का चयन कैसे कर सकता हूं LINQ?

var idList = new int[1, 2, 3, 4, 5];
var userProfiles = _dataContext.UserProfile.Where(......);

मैं यहीं अटक गया। मैं यह छोरों आदि के लिए उपयोग कर सकता हूं, लेकिन मैं इसके साथ ऐसा करूंगा LINQ


4
खोज और खोजना 2 अलग-अलग चीजें हैं। लेकिन जब से आप इंटरनेट पर मेरे कंधे पर देख सकते हैं, क्या आप मुझे बता सकते हैं कि आप कैसे जानते हैं कि मैंने खोज नहीं की? रुको मत बताओ! आपने इसे सही देखा? वही तो मैं कह रहा हूँ।
युस्तमे

5
एक सवाल पूछने से एक खोज करने की तुलना में अधिक समय लगता है। अगली बार बस 'वह / वह' एक खोज किया था या 10
Yustme

2
यह अभी भी काफी ध्यान आकर्षित करता है, इसलिए मैंने सोचा कि मैं उल्लेख करूंगा कि ReSharper उन स्थानों का सुझाव देने का बहुत अच्छा काम करता है जहां आप पुनरावृत्ति कोड को LINQ कथनों में बदल सकते हैं। LINQ में नए लोगों के लिए यह इस उद्देश्य के लिए एक अनिवार्य उपकरण हो सकता है।
युक

जवाबों:


206

आप उसके Contains()लिए उपयोग कर सकते हैं । यह थोड़ा पीछे की ओर महसूस होगा जब आप वास्तव में एक INखंड का उत्पादन करने की कोशिश कर रहे हैं , लेकिन यह करना चाहिए:

var userProfiles = _dataContext.UserProfile
                               .Where(t => idList.Contains(t.Id));

मैं यह भी मान रहा हूं कि प्रत्येक UserProfileरिकॉर्ड में एक int Idक्षेत्र होने वाला है । अगर ऐसा नहीं है, तो आपको उसके अनुसार समायोजित करना होगा।


नमस्ते, हाँ userprofile रिकॉर्ड आईडी के होते हैं। तो किसी तरह मैं t => t.id == idList.Contains (id) जैसा कुछ कर रहा हूँ?
युस्तमे

Contains()idयदि आप उत्तर में लिखा है तो उस समानता को प्रत्येक मूल्य पर जाँचेंगे। ==जब आप एक सेट (सरणी) की वस्तुओं की दूसरे (डेटाबेस तालिका) से तुलना करने की कोशिश कर रहे हों, तो आपको स्पष्ट रूप से कहीं भी लिखने की ज़रूरत नहीं है ।
नीरस

खैर समस्या यह है कि टी उपयोगकर्ताप्रोफाइल की पूरी वस्तु रखती है, और आइडिलिस्ट में केवल इंटेंस है। संकलक ने कुछ के बारे में शिकायत की, लेकिन मैं इसे ठीक करने में कामयाब रहा। धन्यवाद।
युस्तमे

1
@Yuck - मेरे लिए काम नहीं करता, कहते हैं कि समय समाप्त हो गया है! आलसी लोडिंग अक्षम कर दिया है, लेकिन अभी भी विफल रहता है।
भील्विन

1
मुझे "int 'टाइप करने के लिए लैंबडा एक्सप्रेशन को बदल नहीं सकता क्योंकि यह एक प्रतिनिधि प्रकार नहीं है"। उसे कैसे ठीक करें?
स्थिर

90

के साथ समाधान। कहां और। कोटेन्स में ओ (एन स्क्वायर) की जटिलता है। सरल। किसी को भी हैशिंग के कारण बहुत बेहतर प्रदर्शन (ओ (एन के करीब)) होना चाहिए। तो सही कोड है:

_dataContext.UserProfile.Join(idList, up => up.ID, id => id, (up, id) => up);

और अब मेरे माप का परिणाम है। मैंने 100 000 UserProfiles और 100 000 id जनरेट किए। जॉइन में 32ms और लगे। जहां पर। 2 मिनट और 19 सेकंड लगे! मैंने अपने कथन को सिद्ध करने के लिए इस परीक्षण के लिए शुद्ध IEnumerable का उपयोग किया। यदि आप IEnumerable के बजाय सूची का उपयोग करते हैं, तो। और .Contains तेजी से होंगे। वैसे भी अंतर महत्वपूर्ण है। सबसे तेज। जहाँ। सेट के साथ है। यह सब अंतर्निहित सह-निर्माण की जटिलता पर निर्भर करता है। देखो इस पोस्ट के नीचे अपने परीक्षण नमूना पर complexity.Look LINQ के बारे में जानने के लिए:

    private static void Main(string[] args)
    {
        var userProfiles = GenerateUserProfiles();
        var idList = GenerateIds();
        var stopWatch = new Stopwatch();
        stopWatch.Start();
        userProfiles.Join(idList, up => up.ID, id => id, (up, id) => up).ToArray();
        Console.WriteLine("Elapsed .Join time: {0}", stopWatch.Elapsed);
        stopWatch.Restart();
        userProfiles.Where(up => idList.Contains(up.ID)).ToArray();
        Console.WriteLine("Elapsed .Where .Contains time: {0}", stopWatch.Elapsed);
        Console.ReadLine();
    }

    private static IEnumerable<int> GenerateIds()
    {
       // var result = new List<int>();
        for (int i = 100000; i > 0; i--)
        {
            yield return i;
        }
    }

    private static IEnumerable<UserProfile> GenerateUserProfiles()
    {
        for (int i = 0; i < 100000; i++)
        {
            yield return new UserProfile {ID = i};
        }
    }

कंसोल आउटपुट:

बीता हुआ समय। जॉइन्ट टाइम: 00: 00: 00.0322546

बीता हुआ समय। कहीं नहीं। समय: 00: 02: 19.4072107


4
आप संख्या के साथ वापस कर सकते हैं?
युस्टेम

अच्छा है, लेकिन मुझे जिज्ञासु बनाता है कि समय Listका उपयोग क्या होगा । +1
युस्तमे 22

ठीक है, यहाँ आप में रुचि रखते हैं: सूची में 13.1 सेकंड और हैशसेट ने 0,7 एमएस लिया! तो .Where .Contains केवल हैशसेट के मामले में सबसे अच्छा है (जब .Contains में जटिलता O (1) है)। अन्य मामलों में, .Join बेहतर है
डेविड ग्रेगोर

5
Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator.LINQ2SQL डेटाकनेक्ट का उपयोग करते समय मुझे त्रुटि मिलती है।
मयंक रायचुरा

3
@Yustme - प्रदर्शन हमेशा एक विचार है। (मुझे नफरत है कि "यह स्वीकृत उत्तर होना चाहिए" लड़का, लेकिन ...)
jleach

19

अच्छा जवाब देना बंद करो, लेकिन एक महत्वपूर्ण बात मत भूलना - वे अलग परिणाम प्रदान करते हैं!

  var idList = new int[1, 2, 2, 2, 2]; // same user is selected 4 times
  var userProfiles = _dataContext.UserProfile.Where(e => idList.Contains(e)).ToList();

यह DB से 2 पंक्तियाँ लौटाएगा (और यह सही हो सकता है, यदि आप उपयोगकर्ताओं की एक अलग क्रमबद्ध सूची चाहते हैं)

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

  var priceListIDs = new int[1, 2, 2, 2, 2]; // user has bought 4 times item ID 2
  var shoppingCart = _dataContext.ShoppingCart
                     .Join(priceListIDs, sc => sc.PriceListID, pli => pli, (sc, pli) => sc)
                     .ToList();

यह DB से 5 परिणाम लौटाएगा । इस मामले में 'समाहित' का उपयोग करना गलत होगा।


13

यह सरल होना चाहिए। इसे इस्तेमाल करे:

var idList = new int[1, 2, 3, 4, 5];
var userProfiles = _dataContext.UserProfile.Where(e => idList.Contains(e));
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.