LINQ और Lambda के साथ जुड़ें / जहां


457

मुझे LINQ और Lambda में लिखी क्वेरी से परेशानी हो रही है। अब तक, मुझे अपने कोड में बहुत सी त्रुटियाँ हो रही हैं:

int id = 1;
var query = database.Posts.Join(database.Post_Metas,
                                post => database.Posts.Where(x => x.ID == id),
                                meta => database.Post_Metas.Where(x => x.Post_ID == id),
                                (post, meta) => new { Post = post, Meta = meta });

मैं LINQ का उपयोग करने के लिए नया हूं, इसलिए मुझे यकीन नहीं है कि यह प्रश्न सही है।


11
आप क्या खत्म करने की कोशिश कर रहे हैं?
जर्मेन रॉड्रिग्ज

4
आप एक वाक्य में क्या करना चाहते हैं?
शिकारी

6
आपके प्रमुख चयनकर्ता रास्ता बहुत जटिल हैं। यदि आप आईडी से चयन करना चाहते हैं, तो x => x.ID ठीक है।
एरिक लिपर्ट

1
मैं उस पोस्ट के लिए डेटाबेस और मेटा डेटा से एक पोस्ट प्राप्त करना चाहता था।
डेविड

जवाबों:


1053

मुझे लगता है कि यदि आप SQL सिंटैक्स से परिचित हैं, तो LINQ क्वेरी सिंटैक्स का उपयोग करना अधिक स्पष्ट, अधिक स्वाभाविक है, और त्रुटियों को स्पॉट करना आसान बनाता है:

var id = 1;
var query =
   from post in database.Posts
   join meta in database.Post_Metas on post.ID equals meta.Post_ID
   where post.ID == id
   select new { Post = post, Meta = meta };

यदि आप वास्तव में लैम्ब्डा का उपयोग करने पर अड़े हुए हैं, तो आपका सिंटैक्स थोड़ा हटकर है। LINQ एक्सटेंशन मेथड्स का उपयोग करते हुए यहां एक ही क्वेरी दी गई है:

var id = 1;
var query = database.Posts    // your starting point - table in the "from" statement
   .Join(database.Post_Metas, // the source table of the inner join
      post => post.ID,        // Select the primary key (the first part of the "on" clause in an sql "join" statement)
      meta => meta.Post_ID,   // Select the foreign key (the second part of the "on" clause)
      (post, meta) => new { Post = post, Meta = meta }) // selection
   .Where(postAndMeta => postAndMeta.Post.ID == id);    // where statement

10
@Emanuele Greco, आपके संपादन के बारे में, "ID फ़ील्ड पर समानता JOIN स्थिति में सेट है; आपको WHERE क्लॉज़ का उपयोग करने की आवश्यकता नहीं है!": WHERE क्लॉज़ ID फ़ील्ड के बीच समानता का परीक्षण नहीं कर रहा है, यह पोस्ट आईडी के बीच समानता का परीक्षण कर रहा है। कॉलम और आईडी पैरामीटर क्वेरी के बाहर घोषित किया गया।
डेनियल शेफ़र

9
का भयानक टुकड़ा lambdaऔर उपयोग करने और समझने में आसान है
पियोट कुला

1
भयानक उदाहरण
खिलौना 21

1
कभी-कभी मेमने की व्याख्या लंबोदा में लिखी जाती है। अच्छी तरह समझाया।
चुटकी २

80

आप इसके साथ दो तरीके से जा सकते हैं। का उपयोग करते हुए LINQPad और एक डमी डेटाबेस, मैं निम्नलिखित प्रश्नों का निर्माण (अगर आपका LINQ करने के लिए नए अमूल्य):

Posts.Join(
    Post_metas,
    post => post.Post_id,
    meta => meta.Post_id,
    (post, meta) => new { Post = post, Meta = meta }
)

या

from p in Posts
join pm in Post_metas on p.Post_id equals pm.Post_id
select new { Post = p, Meta = pm }

इस विशेष मामले में, मुझे लगता है कि LINQ सिंटैक्स क्लीनर है (मैं दोनों के बीच परिवर्तन करता हूं, जिसके आधार पर पढ़ना सबसे आसान है)।

हालाँकि जो बात मैं बताना चाहता हूँ वह यह है कि यदि आपके डेटाबेस में उपयुक्त विदेशी कुंजियाँ हैं, (पोस्ट और पोस्ट_मेटा के बीच) तो आपको शायद तब तक एक स्पष्ट ज्वाइन की आवश्यकता नहीं है जब तक आप बड़ी संख्या में रिकॉर्ड लोड करने की कोशिश नहीं कर रहे हैं। । आपका उदाहरण इंगित करता है कि आप एक पोस्ट लोड करने की कोशिश कर रहे हैं और यह मेटा डेटा है। यह मानते हुए कि प्रत्येक पोस्ट के लिए कई पोस्ट_मेटा रिकॉर्ड हैं, तो आप निम्न कार्य कर सकते हैं:

var post = Posts.Single(p => p.ID == 1);
var metas = post.Post_metas.ToList();

यदि आप n + 1 समस्या से बचना चाहते हैं, तो आप सभी संबंधित वस्तुओं को एक बार में लोड करने के लिए LINQ से SQL को स्पष्ट रूप से बता सकते हैं (हालाँकि यह तब के लिए एक उन्नत विषय हो सकता है जब आप L2S से अधिक परिचित हों)। नीचे दिए गए उदाहरण में कहा गया है, "जब आप पोस्ट लोड करते हैं, तो इसके साथ जुड़े अपने सभी रिकॉर्ड्स को 'Post_metas' संपत्ति द्वारा प्रदर्शित विदेशी कुंजी के माध्यम से लोड करते हैं:"

var dataLoadOptions = new DataLoadOptions();
dataLoadOptions.LoadWith<Post>(p => p.Post_metas);

var dataContext = new MyDataContext();
dataContext.LoadOptions = dataLoadOptions;

var post = Posts.Single(p => p.ID == 1); // Post_metas loaded automagically

LoadWithएक DataLoadOptionsही प्रकार, या कई अलग-अलग प्रकारों के लिए एक ही सेट पर कई कॉल करना संभव है । यदि आप यह बहुत करते हैं, तो आप बस कैशिंग पर विचार करना चाहते हैं।


1
LinqPad और CRM 2016 ?
क्रिकेनेट

49

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


यह तब काम नहीं करेगा जब आप हमारे जैसे मूल्यों की एक सूची के साथ काम कर रहे हैं। ऑब्जेक्ट पर कोई आईडी प्रॉपर्टी नहीं है।
तल्सफॉमा

मुझे यह वास्तव में उपयोगी लगा, लेकिन मुझे एक त्रुटि मिली जिससे मुझे जुड़ने वाले कॉलम को जोड़ना पड़ा। साथ ही @Mark बायर्स द्वारा पोस्ट किए गए उत्तर को देखते हुए, ज्वाइनिंग कॉलम में Post_IDदूसरे उपनाम में फ़ील्ड है meta => meta.Post_ID। इस चित्रण में उदाहरण में, g.idमूल चयन कथन के भाग JOIN gStatus g on g.idको अंतिम लैंबडा अभिव्यक्ति में दोहराया नहीं गया है।
सॉसेजफिंगर

3
मैं इसे ओपी द्वारा पोस्ट किए गए उत्तर का जवाब देने के लिए आवश्यक वास्तविक लाइनक के संदर्भ के रूप में पोस्ट करने की कोशिश नहीं कर रहा था, यह एसक्यूएल को लिनक प्रारूप में स्थानांतरित करने के लिए एक संदर्भ से अधिक था इसलिए मेरे इनपुट मूल प्रश्न से थोड़ा अलग थे। अगर मैंने gStatus मानों के लिए एक वर्ग बनाया था, तो मैंने उस पर एक id संपत्ति लगाई होगी और फिर हाँ यह g => g के साथ जुड़ जाएगा। मैंने मानों की एक सूची का उपयोग करके कोड को यथासंभव सरल रखने की कोशिश की।
तल्सफॉमा

@ Talspaugh27 तो SQL क्वेरी में g.at पर gStatus क्यों जुड़ता है? क्या वह गलती या इरादतन है?
ड्रामेई

@ एक वर्ग तालिका में डॉमी का प्रत्येक कॉलम में एक नाम होता है, इसलिए चूंकि ये आईडी रखने के लिए कड़ाई से 1 कॉलम तालिका थी, इसलिए मैंने सिर्फ आईडी नाम के एक कॉलम का उपयोग किया था, सूची <int> में वह समस्या नहीं है। अगर मैंने इसे इस तरह सेट public class IdHolder{ int id } किया होता, तो उस वस्तु को gStatus में इस्तेमाल किया List<IdHolder> gStatus = new List<IdHolder>(); gStatus.add(new IdHolder(){id = 7}); gStatus.add(new IdHolder(){id = 8}); होता, तो यह Linq को बदल देता, t =>t.value.TaskStatusId, g=>g.id क्या यह उस अर्थ को बदल देता है?
तल्सपॉफ 27

37

आपके प्रमुख चयनकर्ता गलत हैं। उन्हें विचाराधीन तालिका के प्रकार की एक वस्तु लेनी चाहिए और जुड़ने में उपयोग करने के लिए कुंजी वापस करनी चाहिए। मुझे लगता है कि आप इसका मतलब है:

var query = database.Posts.Join(database.Post_Metas,
                                post => post.ID,
                                meta => meta.Post_ID,
                                (post, meta) => new { Post = post, Meta = meta });

आप बाद में जहां क्लॉज लागू कर सकते हैं, कुंजी चयनकर्ता के हिस्से के रूप में नहीं।


9

पोस्टिंग क्योंकि जब मैंने LINQ + EntityFramework शुरू किया, तो मैंने एक दिन के लिए इन उदाहरणों को देखा।

यदि आप EntityFramework का उपयोग कर रहे हैं, और आपके पास Metaअपने Postमॉडल ऑब्जेक्ट पर सेट की गई नेविगेशन प्रॉपर्टी है , तो यह गंदगी आसान है। यदि आप इकाई का उपयोग कर रहे हैं और आपके पास उस नेविगेशन संपत्ति नहीं है, तो आप किसकी प्रतीक्षा कर रहे हैं?

database
  .Posts
  .Where(post => post.ID == id)
  .Select(post => new { post, post.Meta });

यदि आप पहले कोड कर रहे हैं, तो आप इस प्रकार संपत्ति सेट करेंगे:

class Post {
  [Key]
  public int ID {get; set}
  public int MetaID { get; set; }
  public virtual Meta Meta {get; set;}
}

5

मैंने कुछ ऐसा किया है;

var certificationClass = _db.INDIVIDUALLICENSEs
    .Join(_db.INDLICENSECLAsses,
        IL => IL.LICENSE_CLASS,
        ILC => ILC.NAME,
        (IL, ILC) => new { INDIVIDUALLICENSE = IL, INDLICENSECLAsse = ILC })
    .Where(o => 
        o.INDIVIDUALLICENSE.GLOBALENTITYID == "ABC" &&
        o.INDIVIDUALLICENSE.LICENSE_TYPE == "ABC")
    .Select(t => new
        {
            value = t.PSP_INDLICENSECLAsse.ID,
            name = t.PSP_INDIVIDUALLICENSE.LICENSE_CLASS,                
        })
    .OrderBy(x => x.name);

4

यह कुछ इस तरह हो सकता है

var myvar = from a in context.MyEntity
            join b in context.MyEntity2 on a.key equals b.key
            select new { prop1 = a.prop1, prop2= b.prop1};

1

1 बराबर 1 दो अलग-अलग तालिका में शामिल होते हैं

var query = from post in database.Posts
            join meta in database.Post_Metas on 1 equals 1
            where post.ID == id
            select new { Post = post, Meta = meta };

1

यह linq क्वेरी आपके लिए काम करना चाहिए। इसमें वे सभी पोस्ट मिलेंगे जिनमें पोस्ट मेटा है।

var query = database.Posts.Join(database.Post_Metas,
                                post => post.postId, // Primary Key
                                meta => meat.postId, // Foreign Key
                                (post, meta) => new { Post = post, Meta = meta });

समतुल्य एसक्यूएल क्वेरी

Select * FROM Posts P
INNER JOIN Post_Metas pm ON pm.postId=p.postId

आपने कोष्ठक को बंद कर दिया, जहां तीसरे परम के बाद ... "ज्वाइन के लिए कोई अधिभार तीन तर्क नहीं लेता"
LastTribunal

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