LINQ में LEFT OUTER JOIN करें


538

join-on-equals-intoक्लॉज़ का उपयोग किए बिना ऑब्जेक्ट में C # LINQ में बाईं ओर बाहरी प्रदर्शन कैसे करें ? क्या whereक्लॉज़ के साथ ऐसा करने का कोई तरीका है ? सही समस्या: आंतरिक जुड़ाव के लिए आसान है और मेरे पास इस तरह का एक समाधान है

List<JoinPair> innerFinal = (from l in lefts from r in rights where l.Key == r.Key
                             select new JoinPair { LeftId = l.Id, RightId = r.Id})

लेकिन बाएं बाहरी जुड़ाव के लिए मुझे एक समाधान की आवश्यकता है। मेरा कुछ ऐसा है, लेकिन यह काम नहीं कर रहा है

List< JoinPair> leftFinal = (from l in lefts from r in rights
                             select new JoinPair { 
                                            LeftId = l.Id, 
                                            RightId = ((l.Key==r.Key) ? r.Id : 0
                                        })

जहां JoinPair एक वर्ग है:

public class JoinPair { long leftId; long rightId; }

2
क्या आप इस बात का उदाहरण दे सकते हैं कि आप क्या हासिल करना चाहते हैं?
jeroenh

सामान्य बायाँ बाहरी जुड़ाव कुछ इस तरह है: var a = in bb बी बी में cc पर b.bbbbb के बराबर होता है c.ccccc में dd से dd.DefaultIfEmpty () में चयन करें। bs; मेरा सवाल यह है कि इसमें शामिल होने के लिए कोई भी तरीका क्या है, जो कि ऑन-ऑन-इक्वल-इन का उपयोग करते हुए कुछ इस तरह की धारा a = b से bb में c से c में जहाँ b.bbb == c.cccc ... और इतने पर। ।
टॉय

1
यकीन है कि है, लेकिन आपको अपने कोड का एक उदाहरण पोस्ट करना चाहिए जो आपके पास पहले से है ताकि लोग आपको एक बेहतर जवाब दे सकें
सुस्ती

मैं एक "लेफ्ट को छोड़कर " JOIN की तलाश में था (और मैंने इसे "OUTER" की अवधारणा के साथ भ्रमित किया)। यह जवाब मेरे चाहने के करीब था।
लाल मटर

जवाबों:


597

जैसा कि कहा गया है:

101 LINQ नमूने - बायाँ बाहरी जोड़

var q =
    from c in categories
    join p in products on c.Category equals p.Category into ps
    from p in ps.DefaultIfEmpty()
    select new { Category = c, ProductName = p == null ? "(No products)" : p.ProductName };

7
मैं एक ही बात की कोशिश कर रहा हूं, लेकिन जॉइन ऑपरेटर पर एक त्रुटि हो रही है, जो कहती है "जॉइन क्लॉज में अभिव्यक्तियों में से एक का प्रकार गलत है।"
बधोन जैन Bad

3
@jain अगर आपके प्रकार अलग हैं तो जुड़ने से काम नहीं चलेगा। तो संभावना है कि आपकी चाबियाँ अलग-अलग डेटाटिप्स की हैं। क्या दोनों कुंजियाँ उदाहरण के लिए int हैं?
योआकिम

2
समाधान जैन? मैं भी उसी त्रुटि का सामना कर रहा हूं और मेरे मामले में भी प्रकार समान हैं।
संदीप

1
@ संदीप अपनी कुंजियों की जांच करें जहां आप इसमें शामिल हुए थे। मान लीजिए अगर वे प्रकार स्ट्रिंग और इंट के हैं तो स्ट्रिंग स्ट्रिंग को इंट में बदलें।
अंकित


546

यदि एक डेटाबेस संचालित LINQ प्रदाता का उपयोग किया जाता है, तो एक बहुत अधिक पठनीय बायाँ बाहरी जुड़ाव इस तरह लिखा जा सकता है:

from maintable in Repo.T_Whatever 
from xxx in Repo.T_ANY_TABLE.Where(join condition).DefaultIfEmpty()

यदि आप छोड़ देते हैं तो DefaultIfEmpty()आपके पास एक आंतरिक जुड़ाव होगा।

स्वीकृत उत्तर लें:

  from c in categories
    join p in products on c equals p.Category into ps
    from p in ps.DefaultIfEmpty()

यह वाक्यविन्यास बहुत भ्रामक है, और यह स्पष्ट नहीं है कि जब आप MULTIPLE तालिकाओं में शामिल होना चाहते हैं तो यह कैसे काम करता है।

नोट
यह ध्यान दिया जाना चाहिए कि from alias in Repo.whatever.Where(condition).DefaultIfEmpty()बाहरी-लागू / बाएं-ज्वाइन-लेटरल के समान है, जो किसी भी (सभ्य) डेटाबेस-अनुकूलक पूरी तरह से बाईं पंक्ति में अनुवाद करने में सक्षम है, जब तक आप प्रति पंक्ति परिचय नहीं करते हैं -वेल्स (उर्फ एक वास्तविक बाहरी लागू)। Linq-2-Objects में ऐसा न करें (क्योंकि जब आप Linq-to-Objects का उपयोग करते हैं तो कोई DB-अनुकूलक नहीं होता है)।

विस्तृत उदाहरण

var query2 = (
    from users in Repo.T_User
    from mappings in Repo.T_User_Group
         .Where(mapping => mapping.USRGRP_USR == users.USR_ID)
         .DefaultIfEmpty() // <== makes join left join
    from groups in Repo.T_Group
         .Where(gruppe => gruppe.GRP_ID == mappings.USRGRP_GRP)
         .DefaultIfEmpty() // <== makes join left join

    // where users.USR_Name.Contains(keyword)
    // || mappings.USRGRP_USR.Equals(666)  
    // || mappings.USRGRP_USR == 666 
    // || groups.Name.Contains(keyword)

    select new
    {
         UserId = users.USR_ID
        ,UserName = users.USR_User
        ,UserGroupId = groups.ID
        ,GroupName = groups.Name
    }

);


var xy = (query2).ToList();

जब LINQ 2 SQL के साथ प्रयोग किया जाता है, तो यह निम्नलिखित बहुत सुपाठ्य SQL क्वेरी का अच्छी तरह से अनुवाद करेगा:

SELECT 
     users.USR_ID AS UserId 
    ,users.USR_User AS UserName 
    ,groups.ID AS UserGroupId 
    ,groups.Name AS GroupName 
FROM T_User AS users

LEFT JOIN T_User_Group AS mappings
   ON mappings.USRGRP_USR = users.USR_ID

LEFT JOIN T_Group AS groups
    ON groups.GRP_ID == mappings.USRGRP_GRP

संपादित करें:

अधिक जटिल उदाहरण के लिए " SQL सर्वर क्वेरी को Linq क्वेरी में परिवर्तित करें " भी देखें ।

इसके अलावा, यदि आप इसे Linq-2-Objects (Linq-2-SQL के बजाय) में कर रहे हैं, तो आपको इसे पुराने ज़माने के तरीके से करना चाहिए (क्योंकि LINQ to SQL इसे संचालन में शामिल होने के लिए सही तरीके से अनुवादित करता है, लेकिन ऑब्जेक्ट्स पर यह विधि एक पूर्ण स्कैन को बल देता है, और इंडेक्स खोजों का लाभ नहीं उठाता है, क्यों ...):

    var query2 = (
    from users in Repo.T_Benutzer
    join mappings in Repo.T_Benutzer_Benutzergruppen on mappings.BEBG_BE equals users.BE_ID into tmpMapp
    join groups in Repo.T_Benutzergruppen on groups.ID equals mappings.BEBG_BG into tmpGroups
    from mappings in tmpMapp.DefaultIfEmpty()
    from groups in tmpGroups.DefaultIfEmpty()
    select new
    {
         UserId = users.BE_ID
        ,UserName = users.BE_User
        ,UserGroupId = mappings.BEBG_BG
        ,GroupName = groups.Name
    }

);

21
यह उत्तर वास्तव में मददगार है। वास्तव में समझने योग्य वाक्य रचना प्रदान करने के लिए धन्यवाद।
बजे क्रिस मैरिसिक

3
WTB एक NHibernate संगत LINQ क्वेरी ... :)
mxmissile

30
LINQ to SQL ऑपरेशंस में शामिल होने के लिए इसे सही तरीके से ट्रांसलेट करता है। हालाँकि यह ऑब्जेक्ट पूर्ण स्कैन पर बल देता है, यही कारण है कि आधिकारिक दस्तावेज़ीकरण समूह को समाधान में शामिल होने का प्रस्ताव देता है जो हैश का लाभ उठाकर अनुक्रमणिका खोजों में ले जा सकता है।
तामीर दानीली ५'१५ को

3
मुझे लगता है कि स्पष्ट joinका वाक्य-विन्यास बहुत अधिक पठनीय और स्पष्ट है, whereइसके बादDefaultIfEmpty
FindOut_Quran

1
@ user3441905: जब तक आपको टेबल बी के साथ तालिका में शामिल होना है, तब तक यह हो सकता है। लेकिन जैसे ही आपके पास इससे अधिक है, यह नहीं होगा। लेकिन यहां तक ​​कि केवल 2 तालिका के लिए, मुझे लगता है कि यह अत्यधिक क्रियात्मक है। लोकप्रिय राय भी आपके खिलाफ लगती है, क्योंकि यह उत्तर 0 से शुरू हुआ जब शीर्ष उत्तर में पहले से ही 90+ अपवोट थे।
स्टीफन स्टीगर

131

लंबोदर अभिव्यक्ति का उपयोग करना

db.Categories    
  .GroupJoin(db.Products,
      Category => Category.CategoryId,
      Product => Product.CategoryId,
      (x, y) => new { Category = x, Products = y })
  .SelectMany(
      xy => xy.Products.DefaultIfEmpty(),
      (x, y) => new { Category = x.Category, Product = y })
  .Select(s => new
  {
      CategoryName = s.Category.Name,     
      ProductName = s.Product.Name   
  });

8
Join and GroupJoin दोनों वास्तव में लेफ्ट-जॉइन का समर्थन नहीं करते हैं। GroupJoin का उपयोग करने के साथ चाल यह है कि आपके पास खाली समूह हो सकते हैं और फिर उन खाली समूहों को खाली मानों में अनुवाद कर सकते हैं। DefaultIfEmpty बस यही करता है, जिसका अर्थ Enumerable.Empty<Product>.DefaultIfEmpty()एक IEnumerable के एकल मान के साथ वापस आ जाएगा default(Product)
तामीर दानीली

61
यह सब एक लेफ्ट जॉइन करने के लिए ??
FindOut_Quran

7
इसके लिए धन्यवाद! बहुत सारे लैम्ब्डा अभिव्यक्ति के उदाहरण वहां नहीं हैं, यह मेरे लिए काम करता है।
जोहान हेनकेन्स

1
जवाब के लिए धन्यवाद। यह कच्चे एसक्यूएल LEFT OUTER JOIN के लिए सबसे करीबी चीज़ है जो मैंने वर्षों में लिखी है
जॉन गैथोगो

1
वास्तव में अंतिम चयन () की जरूरत नहीं है, SelectMany () में anon obj उसी आउटपुट के लिए फिर से शुरू किया जा सकता है। एक और विचार यह है कि एक करीबी LEFT JOIN तुल्यता का अनुकरण करने के लिए n का परीक्षण करें।
डेनी जैकब

46

अब विस्तार विधि के रूप में:

public static class LinqExt
{
    public static IEnumerable<TResult> LeftOuterJoin<TLeft, TRight, TKey, TResult>(this IEnumerable<TLeft> left, IEnumerable<TRight> right, Func<TLeft, TKey> leftKey, Func<TRight, TKey> rightKey,
        Func<TLeft, TRight, TResult> result)
    {
        return left.GroupJoin(right, leftKey, rightKey, (l, r) => new { l, r })
             .SelectMany(
                 o => o.r.DefaultIfEmpty(),
                 (l, r) => new { lft= l.l, rght = r })
             .Select(o => result.Invoke(o.lft, o.rght));
    }
}

जैसे आप सामान्य रूप से जुड़ने का उपयोग करेंगे, वैसे ही उपयोग करें:

var contents = list.LeftOuterJoin(list2, 
             l => l.country, 
             r => r.name,
            (l, r) => new { count = l.Count(), l.country, l.reason, r.people })

आशा है कि यह आपको कुछ समय बचाता है।


44

इस उदाहरण पर एक नज़र डालें । इस क्वेरी को काम करना चाहिए:

var leftFinal = from left in lefts
                join right in rights on left equals right.Left into leftRights
                from leftRight in leftRights.DefaultIfEmpty()
                select new { LeftId = left.Id, RightId = left.Key==leftRight.Key ? leftRight.Id : 0 };

3
rमें शामिल होने के बाद चुनिंदा खंड में पहुँचा जा सकता है?
फरहाद अलीजादे नूरी

@ फरहाद अलीजादे नूरी हां यह कर सकते हैं।
पो-टा-पैर की अंगुली

लेखक शायद rदूसरे fromखंड में फिर से उपयोग करने के लिए था । यानी from r in lrs.DefaultIfEmpty()अन्यथा इस क्वेरी ज्यादा मतलब नहीं है और शायद भी की वजह से संकलन नहीं है rका चयन के लिए संदर्भ से बाहर किया जा रहा है।
साब अमीनी

@ डेवार्ट, जब मैंने आपकी क्वेरी पढ़ी तो उसने मुझे Clockwiseजॉन क्लेज़ के साथ फिल्म की याद दिला दी , योग्य।
माटस वैतकेविसियस

1
बाएं से बाएं तरफ के राइट्स में राइट से लेफ्ट राइट्स में ... ओह जीज ... LINQ में LEFT OUTER JOIN का इस्तेमाल करने का सिंटैक्स वास्तव में स्पष्ट नहीं है, लेकिन ये नाम वास्तव में इसे और भी अस्पष्ट बनाते हैं।
माइक गिल्डहिल

19

एक्सटेंशन विधियों द्वारा बाएं बाहरी जुड़ने का कार्यान्वयन जैसा दिख सकता है

public static IEnumerable<Result> LeftJoin<TOuter, TInner, TKey, Result>(
  this IEnumerable<TOuter> outer, IEnumerable<TInner> inner
  , Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector
  , Func<TOuter, TInner, Result> resultSelector, IEqualityComparer<TKey> comparer)
  {
    if (outer == null)
      throw new ArgumentException("outer");

    if (inner == null)
      throw new ArgumentException("inner");

    if (outerKeySelector == null)
      throw new ArgumentException("outerKeySelector");

    if (innerKeySelector == null)
      throw new ArgumentException("innerKeySelector");

    if (resultSelector == null)
      throw new ArgumentException("resultSelector");

    return LeftJoinImpl(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer ?? EqualityComparer<TKey>.Default);
  }

  static IEnumerable<Result> LeftJoinImpl<TOuter, TInner, TKey, Result>(
      IEnumerable<TOuter> outer, IEnumerable<TInner> inner
      , Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector
      , Func<TOuter, TInner, Result> resultSelector, IEqualityComparer<TKey> comparer)
  {
    var innerLookup = inner.ToLookup(innerKeySelector, comparer);

    foreach (var outerElment in outer)
    {
      var outerKey = outerKeySelector(outerElment);
      var innerElements = innerLookup[outerKey];

      if (innerElements.Any())
        foreach (var innerElement in innerElements)
          yield return resultSelector(outerElment, innerElement);
      else
        yield return resultSelector(outerElment, default(TInner));
     }
   }

इसके बाद परिणाम देने वाले को अशक्त तत्वों का ध्यान रखना पड़ता है। Fx।

   static void Main(string[] args)
   {
     var inner = new[] { Tuple.Create(1, "1"), Tuple.Create(2, "2"), Tuple.Create(3, "3") };
     var outer = new[] { Tuple.Create(1, "11"), Tuple.Create(2, "22") };

     var res = outer.LeftJoin(inner, item => item.Item1, item => item.Item1, (it1, it2) =>
     new { Key = it1.Item1, V1 = it1.Item2, V2 = it2 != null ? it2.Item2 : default(string) });

     foreach (var item in res)
       Console.WriteLine(string.Format("{0}, {1}, {2}", item.Key, item.V1, item.V2));
   }

4
यह केवल LINQ ऑब्जेक्ट्स के लिए एक विकल्प है, और किसी भी क्वेरी प्रदाताओं को क्वेरी का अनुवाद करने में सक्षम नहीं होगा, जो इस ऑपरेशन के लिए सबसे आम उपयोग मामला है।
सेरी

13
लेकिन सवाल यह था कि "सी # LINQ ऑब्जेक्ट्स में लेफ्ट ऑउट जॉइन कैसे करें ..."
बर्ट्रेंड

12

इस उदाहरण को देखें

class Person
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Phone { get; set; }
}

class Pet
{
    public string Name { get; set; }
    public Person Owner { get; set; }
}

public static void LeftOuterJoinExample()
{
    Person magnus = new Person {ID = 1, FirstName = "Magnus", LastName = "Hedlund"};
    Person terry = new Person {ID = 2, FirstName = "Terry", LastName = "Adams"};
    Person charlotte = new Person {ID = 3, FirstName = "Charlotte", LastName = "Weiss"};
    Person arlene = new Person {ID = 4, FirstName = "Arlene", LastName = "Huff"};

    Pet barley = new Pet {Name = "Barley", Owner = terry};
    Pet boots = new Pet {Name = "Boots", Owner = terry};
    Pet whiskers = new Pet {Name = "Whiskers", Owner = charlotte};
    Pet bluemoon = new Pet {Name = "Blue Moon", Owner = terry};
    Pet daisy = new Pet {Name = "Daisy", Owner = magnus};

    // Create two lists.
    List<Person> people = new List<Person> {magnus, terry, charlotte, arlene};
    List<Pet> pets = new List<Pet> {barley, boots, whiskers, bluemoon, daisy};

    var query = from person in people
        where person.ID == 4
        join pet in pets on person equals pet.Owner  into personpets
        from petOrNull in personpets.DefaultIfEmpty()
        select new { Person=person, Pet = petOrNull}; 



    foreach (var v in query )
    {
        Console.WriteLine("{0,-15}{1}", v.Person.FirstName + ":", (v.Pet == null ? "Does not Exist" : v.Pet.Name));
    }
}

// This code produces the following output:
//
// Magnus:        Daisy
// Terry:         Barley
// Terry:         Boots
// Terry:         Blue Moon
// Charlotte:     Whiskers
// Arlene:

अब आप include elements from the leftभले ही उस तत्व के लिए सक्षम हों has no matches in the right, हमारे मामले में हमने Arleneउसे पीछे छोड़ दिया, यहां तक ​​कि उसके पास कोई मेल नहीं है

यहाँ संदर्भ है

कैसे करें: बायां बाहरी जोड़ प्रदर्शन करें (C # प्रोग्रामिंग गाइड)


आउटपुट होना चाहिए: आर्लीन:
एक्ज़िस्ट

10

यह सामान्य रूप है (जैसा कि पहले से ही अन्य उत्तरों में प्रदान किया गया है)

var c =
    from a in alpha
    join b in beta on b.field1 equals a.field1 into b_temp
    from b_value in b_temp.DefaultIfEmpty()
    select new { Alpha = a, Beta = b_value };

हालाँकि यहाँ एक स्पष्टीकरण है कि मुझे आशा है कि यह स्पष्ट रूप से इसका क्या अर्थ होगा!

join b in beta on b.field1 equals a.field1 into b_temp

अनिवार्य रूप से एक अलग परिणाम सेट b_temp बनाता है जिसमें दाहिने हाथ की तरफ ('b' में प्रविष्टियाँ) प्रविष्टियों के लिए प्रभावी रूप से अशक्त 'पंक्तियाँ' शामिल हैं।

फिर अगली पंक्ति:

from b_value in b_temp.DefaultIfEmpty()

.. उस परिणाम पर सेट करता है, दाहिने हाथ की ओर 'पंक्ति' के लिए डिफ़ॉल्ट अशक्त मान सेट करता है, और दाहिने हाथ की ओर पंक्ति का परिणाम सेट करने के लिए 'b_value' के मूल्य में शामिल हो जाता है (यानी वह मूल्य जो दाईं ओर है यदि कोई मिलान रिकॉर्ड है, या 'शून्य' नहीं है, तो हाथ की ओर।

अब, यदि दाहिने हाथ की तरफ एक अलग LINQ क्वेरी का परिणाम है, तो इसमें अनाम प्रकार शामिल होंगे, जो केवल 'कुछ' या 'अशक्त' हो सकता है। यदि यह एक उल्लेखनीय है, लेकिन (उदाहरण के लिए एक सूची - जहाँ MyObjectB 2 क्षेत्रों के साथ एक वर्ग है), तो इसके गुणों के लिए डिफ़ॉल्ट 'अशक्त' मान का उपयोग करने के बारे में विशिष्ट होना संभव है:

var c =
    from a in alpha
    join b in beta on b.field1 equals a.field1 into b_temp
    from b_value in b_temp.DefaultIfEmpty( new MyObjectB { Field1 = String.Empty, Field2 = (DateTime?) null })
    select new { Alpha = a, Beta_field1 = b_value.Field1, Beta_field2 = b_value.Field2 };

यह सुनिश्चित करता है कि 'b' स्वयं शून्य नहीं है (लेकिन इसके गुण शून्य हो सकते हैं, आपके द्वारा निर्दिष्ट डिफ़ॉल्ट शून्य मानों का उपयोग करके), और यह आपको b_value के गुणों को b_value के लिए एक शून्य संदर्भ अपवाद प्राप्त किए बिना जांचने की अनुमति देता है। ध्यान दें कि एक अशक्त DateTime के लिए, एक प्रकार का (DateTime?) अर्थात 'nullable DateTime' को 'DefaultIfEmpty' के लिए विनिर्देशन में null के 'प्रकार' के रूप में निर्दिष्ट किया जाना चाहिए (यह उन प्रकारों पर भी लागू होगा जो 'मूल रूप से नहीं हैं' 'अशक्त उदा। डबल, फ्लोट)।

आप उपर्युक्त वाक्यविन्यास का उपयोग करके कई बाहरी बाहरी जोड़ दिखा सकते हैं।


1
b_value कहाँ से आता है?
जैक फ्रेजर

9

यदि आपको 2 से अधिक तालिकाओं में शामिल होने की आवश्यकता है, तो यहां एक उदाहरण दिया गया है:

from d in context.dc_tpatient_bookingd
join bookingm in context.dc_tpatient_bookingm 
     on d.bookingid equals bookingm.bookingid into bookingmGroup
from m in bookingmGroup.DefaultIfEmpty()
join patient in dc_tpatient
     on m.prid equals patient.prid into patientGroup
from p in patientGroup.DefaultIfEmpty()

Ref: https://stackoverflow.com/a/17142392/2343


4

एक्सटेंशन विधि जो बायीं तरह काम करती है, ज्वाइन सिंटैक्स के साथ जुड़ें

public static class LinQExtensions
{
    public static IEnumerable<TResult> LeftJoin<TOuter, TInner, TKey, TResult>(
        this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, 
        Func<TOuter, TKey> outerKeySelector, 
        Func<TInner, TKey> innerKeySelector, 
        Func<TOuter, TInner, TResult> resultSelector)
    {
        return outer.GroupJoin(
            inner, 
            outerKeySelector, 
            innerKeySelector,
            (outerElement, innerElements) => resultSelector(outerElement, innerElements.FirstOrDefault()));
    }
}

बस इसे .NET कोर में लिखा है और यह उम्मीद के मुताबिक काम कर रहा है।

छोटा परीक्षण:

        var Ids = new List<int> { 1, 2, 3, 4};
        var items = new List<Tuple<int, string>>
        {
            new Tuple<int, string>(1,"a"),
            new Tuple<int, string>(2,"b"),
            new Tuple<int, string>(4,"d"),
            new Tuple<int, string>(5,"e"),
        };

        var result = Ids.LeftJoin(
            items,
            id => id,
            item => item.Item1,
            (id, item) => item ?? new Tuple<int, string>(id, "not found"));

        result.ToList()
        Count = 4
        [0]: {(1, a)}
        [1]: {(2, b)}
        [2]: {(3, not found)}
        [3]: {(4, d)}

4

यहाँ विधि सिंटैक्स का उपयोग करके संस्करण को समझना काफी आसान है:

IEnumerable<JoinPair> outerLeft =
    lefts.SelectMany(l => 
        rights.Where(r => l.Key == r.Key)
              .DefaultIfEmpty(new Item())
              .Select(r => new JoinPair { LeftId = l.Id, RightId = r.Id }));

3

तीन टेबल हैं: व्यक्ति, स्कूल और person_schools, जो व्यक्तियों को उन स्कूलों से जोड़ता है, जिनमें वे अध्ययन करते हैं। आईडी = 6 वाले व्यक्ति का एक संदर्भ तालिका person_schools में अनुपस्थित है। हालाँकि, id = 6 वाले व्यक्ति को परिणाम lef-join ग्रिड में प्रस्तुत किया गया है।

List<Person> persons = new List<Person>
{
    new Person { id = 1, name = "Alex", phone = "4235234" },
    new Person { id = 2, name = "Bob", phone = "0014352" },
    new Person { id = 3, name = "Sam", phone = "1345" },
    new Person { id = 4, name = "Den", phone = "3453452" },
    new Person { id = 5, name = "Alen", phone = "0353012" },
    new Person { id = 6, name = "Simon", phone = "0353012" }
};

List<School> schools = new List<School>
{
    new School { id = 1, name = "Saint. John's school"},
    new School { id = 2, name = "Public School 200"},
    new School { id = 3, name = "Public School 203"}
};

List<PersonSchool> persons_schools = new List<PersonSchool>
{
    new PersonSchool{id_person = 1, id_school = 1},
    new PersonSchool{id_person = 2, id_school = 2},
    new PersonSchool{id_person = 3, id_school = 3},
    new PersonSchool{id_person = 4, id_school = 1},
    new PersonSchool{id_person = 5, id_school = 2}
    //a relation to the person with id=6 is absent
};

var query = from person in persons
            join person_school in persons_schools on person.id equals person_school.id_person
            into persons_schools_joined
            from person_school_joined in persons_schools_joined.DefaultIfEmpty()
            from school in schools.Where(var_school => person_school_joined == null ? false : var_school.id == person_school_joined.id_school).DefaultIfEmpty()
            select new { Person = person.name, School = school == null ? String.Empty : school.name };

foreach (var elem in query)
{
    System.Console.WriteLine("{0},{1}", elem.Person, elem.School);
}

हालांकि यह शायद सवाल का जवाब आपके उत्तर के बारे में कुछ स्पष्टीकरण प्रदान करता है :)
अमीर

2

यह एक SQL सिंटैक्स है जो आंतरिक और बाएं बाहरी जॉइन के लिए LINQ सिंटैक्स की तुलना करता है। बाईं ओर का बाहरी जोड़:

http://www.ozkary.com/2011/07/linq-to-entity-inner-and-left-joins.html

"निम्न उदाहरण एक समूह उत्पाद और श्रेणी के बीच जुड़ता है। यह अनिवार्य रूप से बाईं ओर है। अभिव्यक्ति तालिका तालिका खाली होने पर भी डेटा लौटाती है। श्रेणी तालिका के गुणों का उपयोग करने के लिए, हमें अब परिणाम से चयन करना होगा। catList.DefaultIfEmpty () स्टेटमेंट में सीएल से जोड़कर।


1

Linq C # // में बाईं ओर के बाहरी प्रदर्शन करें

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

class Child
{
    public string Name { get; set; }
    public Person Owner { get; set; }
}
public class JoinTest
{
    public static void LeftOuterJoinExample()
    {
        Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
        Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
        Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
        Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };

        Child barley = new Child { Name = "Barley", Owner = terry };
        Child boots = new Child { Name = "Boots", Owner = terry };
        Child whiskers = new Child { Name = "Whiskers", Owner = charlotte };
        Child bluemoon = new Child { Name = "Blue Moon", Owner = terry };
        Child daisy = new Child { Name = "Daisy", Owner = magnus };

        // Create two lists.
        List<Person> people = new List<Person> { magnus, terry, charlotte, arlene };
        List<Child> childs = new List<Child> { barley, boots, whiskers, bluemoon, daisy };

        var query = from person in people
                    join child in childs
                    on person equals child.Owner into gj
                    from subpet in gj.DefaultIfEmpty()
                    select new
                    {
                        person.FirstName,
                        ChildName = subpet!=null? subpet.Name:"No Child"
                    };
                       // PetName = subpet?.Name ?? String.Empty };

        foreach (var v in query)
        {
            Console.WriteLine($"{v.FirstName + ":",-25}{v.ChildName}");
        }
    }

    // This code produces the following output:
    //
    // Magnus:        Daisy
    // Terry:         Barley
    // Terry:         Boots
    // Terry:         Blue Moon
    // Charlotte:     Whiskers
    // Arlene:        No Child

https://dotnetwithhamid.blogspot.in/


1

मैं यह जोड़ना चाहूंगा कि यदि आपको MoreLinq एक्सटेंशन मिलता है तो अब समरूप और विषम दोनों के लिए समर्थन उपलब्ध है

http://morelinq.github.io/2.8/ref/api/html/Overload_MoreLinq_MoreEnumerable_LeftJoin.htm

उदाहरण:

//Pretend a ClientCompany object and an Employee object both have a ClientCompanyID key on them

return DataContext.ClientCompany
    .LeftJoin(DataContext.Employees,                         //Table being joined
        company => company.ClientCompanyID,                  //First key
        employee => employee.ClientCompanyID,                //Second Key
        company => new {company, employee = (Employee)null}, //Result selector when there isn't a match
        (company, employee) => new { company, employee });   //Result selector when there is a match

संपादित करें:

पूर्वव्यापी में यह काम कर सकता है, लेकिन यह IQueryable को IEnumerable में रूपांतरित करता है क्योंकि morelinq SQL में क्वेरी को परिवर्तित नहीं करता है।

आप यहाँ वर्णित के रूप में एक GroupJoin का उपयोग कर सकते हैं: https://stackoverflow.com/a/24273804/4251433

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


1

आसान तरीका यह है कि Let कीवर्ड का उपयोग करें। यह मेरे लिए काम करता है।

from AItem in Db.A
Let BItem = Db.B.Where(x => x.id == AItem.id ).FirstOrDefault() 
Where SomeCondition
Select new YourViewModel
{
    X1 = AItem.a,
    X2 = AItem.b,
    X3 = BItem.c
}

यह लेफ्ट जॉइन का अनुकरण है। यदि B तालिका में प्रत्येक आइटम A आइटम से मेल नहीं खाता है, तो BItem रिक्त है


0

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

इस स्थिति में यदि मैं ज्वाइनिंग कंडीशन में करता हूं तो जो पंक्तियां वापस आती हैं उन्हें कम करता हूं।

टर्नरी स्थिति का उपयोग किया जाता है (= n == null ? "__" : n.MonDayNote,)

  • यदि ऑब्जेक्ट है null(तो कोई मिलान नहीं), तो उसके बाद जो है उसे वापस करें ?__, इस मामले में।

  • वरना, वापसी के बाद क्या है :, n.MonDayNote

अन्य योगदानकर्ताओं के लिए धन्यवाद, जहां मैंने अपने मुद्दे के साथ शुरुआत की है।


        var schedLocations = (from f in db.RAMS_REVENUE_LOCATIONS
              join n in db.RAMS_LOCATION_PLANNED_MANNING on f.revenueCenterID equals

                  n.revenueCenterID into lm

              from n in lm.DefaultIfEmpty()

              join r in db.RAMS_LOCATION_SCHED_NOTE on f.revenueCenterID equals r.revenueCenterID
              into locnotes

              from r in locnotes.DefaultIfEmpty()
              where f.LocID == nLocID && f.In_Use == true && f.revenueCenterID > 1000

              orderby f.Areano ascending, f.Locname ascending
              select new
              {
                  Facname = f.Locname,
                  f.Areano,
                  f.revenueCenterID,
                  f.Locabbrev,

                  //  MonNote = n == null ? "__" : n.MonDayNote,
                  MonNote = n == null ? "__" : n.MonDayNote,
                  TueNote = n == null ? "__" : n.TueDayNote,
                  WedNote = n == null ? "__" : n.WedDayNote,
                  ThuNote = n == null ? "__" : n.ThuDayNote,

                  FriNote = n == null ? "__" : n.FriDayNote,
                  SatNote = n == null ? "__" : n.SatDayNote,
                  SunNote = n == null ? "__" : n.SunDayNote,
                  MonEmpNbr = n == null ? 0 : n.MonEmpNbr,
                  TueEmpNbr = n == null ? 0 : n.TueEmpNbr,
                  WedEmpNbr = n == null ? 0 : n.WedEmpNbr,
                  ThuEmpNbr = n == null ? 0 : n.ThuEmpNbr,
                  FriEmpNbr = n == null ? 0 : n.FriEmpNbr,
                  SatEmpNbr = n == null ? 0 : n.SatEmpNbr,
                  SunEmpNbr = n == null ? 0 : n.SunEmpNbr,
                  SchedMondayDate = n == null ? dMon : n.MondaySchedDate,
                  LocNotes = r == null ? "Notes: N/A" : r.LocationNote

              }).ToList();
                Func<int, string> LambdaManning = (x) => { return x == 0 ? "" : "Manning:" + x.ToString(); };
        DataTable dt_ScheduleMaster = PsuedoSchedule.Tables["ScheduleMasterWithNotes"];
        var schedLocations2 = schedLocations.Where(x => x.SchedMondayDate == dMon);

0
class Program
{
    List<Employee> listOfEmp = new List<Employee>();
    List<Department> listOfDepart = new List<Department>();

    public Program()
    {
        listOfDepart = new List<Department>(){
            new Department { Id = 1, DeptName = "DEV" },
            new Department { Id = 2, DeptName = "QA" },
            new Department { Id = 3, DeptName = "BUILD" },
            new Department { Id = 4, DeptName = "SIT" }
        };


        listOfEmp = new List<Employee>(){
            new Employee { Empid = 1, Name = "Manikandan",DepartmentId=1 },
            new Employee { Empid = 2, Name = "Manoj" ,DepartmentId=1},
            new Employee { Empid = 3, Name = "Yokesh" ,DepartmentId=0},
            new Employee { Empid = 3, Name = "Purusotham",DepartmentId=0}
        };

    }
    static void Main(string[] args)
    {
        Program ob = new Program();
        ob.LeftJoin();
        Console.ReadLine();
    }

    private void LeftJoin()
    {
        listOfEmp.GroupJoin(listOfDepart.DefaultIfEmpty(), x => x.DepartmentId, y => y.Id, (x, y) => new { EmpId = x.Empid, EmpName = x.Name, Dpt = y.FirstOrDefault() != null ? y.FirstOrDefault().DeptName : null }).ToList().ForEach
            (z =>
            {
                Console.WriteLine("Empid:{0} EmpName:{1} Dept:{2}", z.EmpId, z.EmpName, z.Dpt);
            });
    }
}

class Employee
{
    public int Empid { get; set; }
    public string Name { get; set; }
    public int DepartmentId { get; set; }
}

class Department
{
    public int Id { get; set; }
    public string DeptName { get; set; }
}

आउटपुट


0

इसी तरह के एक सवाल के मेरे जवाब के अनुसार, यहां:

Linq से SQL बायीं ओर बाहरी लैम्बडा सिंटैक्स का उपयोग कर जुड़ती है और 2 कॉलम पर जुड़ती है (कम्पोजिट जॉइन की)

यहाँ कोड प्राप्त करें , या मेरे गिथब रेपो को क्लोन करें , और खेलें!

प्रश्न:

        var petOwners =
            from person in People
            join pet in Pets
            on new
            {
                person.Id,
                person.Age,
            }
            equals new
            {
                pet.Id,
                Age = pet.Age * 2, // owner is twice age of pet
            }
            into pets
            from pet in pets.DefaultIfEmpty()
            select new PetOwner
            {
                Person = person,
                Pet = pet,
            };

लैम्ब्डा:

        var petOwners = People.GroupJoin(
            Pets,
            person => new { person.Id, person.Age },
            pet => new { pet.Id, Age = pet.Age * 2 },
            (person, pet) => new
            {
                Person = person,
                Pets = pet,
            }).SelectMany(
            pet => pet.Pets.DefaultIfEmpty(),
            (people, pet) => new
            {
                people.Person,
                Pet = pet,
            });

0

अवलोकन: इस कोड स्निपेट में, मैं आईडी द्वारा समूह में कैसे प्रदर्शित करता हूं, जहां टेबल 1 और टेबल 2 में कई संबंध हैं। मैं Id, Field1 और Field2 पर समूह बनाता हूं। उपनगर मददगार होता है, अगर तीसरे टेबल लुकअप की आवश्यकता होती है और इसके लिए लेफ्ट जॉइन रिलेशनशिप की आवश्यकता होती है। मैं एक समूह में शामिल होने के लिए एक बाईं ओर और एक उपनगर लाइनक दिखाता हूं। परिणाम बराबर हैं।

class MyView
{
public integer Id {get,set};
    public String Field1  {get;set;}
public String Field2 {get;set;}
    public String SubQueryName {get;set;}                           
}

IList<MyView> list = await (from ci in _dbContext.Table1
                                               join cii in _dbContext.Table2
                                                   on ci.Id equals cii.Id

                                               where ci.Field1 == criterion
                                               group new
                                               {
                                                   ci.Id
                                               } by new { ci.Id, cii.Field1, ci.Field2}

                                           into pg
                                               select new MyView
                                               {
                                                   Id = pg.Key.Id,
                                                   Field1 = pg.Key.Field1,
                                                   Field2 = pg.Key.Field2,
                                                   SubQueryName=
                                                   (from chv in _dbContext.Table3 where chv.Id==pg.Key.Id select chv.Field1).FirstOrDefault()
                                               }).ToListAsync<MyView>();


 Compared to using a Left Join and Group new

IList<MyView> list = await (from ci in _dbContext.Table1
                                               join cii in _dbContext.Table2
                                                   on ci.Id equals cii.Id

                       join chv in _dbContext.Table3
                                                  on cii.Id equals chv.Id into lf_chv
                                                from chv in lf_chv.DefaultIfEmpty()

                                               where ci.Field1 == criterion
                                               group new
                                               {
                                                   ci.Id
                                               } by new { ci.Id, cii.Field1, ci.Field2, chv.FieldValue}

                                           into pg
                                               select new MyView
                                               {
                                                   Id = pg.Key.Id,
                                                   Field1 = pg.Key.Field1,
                                                   Field2 = pg.Key.Field2,
                                                   SubQueryName=pg.Key.FieldValue
                                               }).ToListAsync<MyView>();

-1
(from a in db.Assignments
     join b in db.Deliveryboys on a.AssignTo equals b.EmployeeId  

     //from d in eGroup.DefaultIfEmpty()
     join  c in  db.Deliveryboys on a.DeliverTo equals c.EmployeeId into eGroup2
     from e in eGroup2.DefaultIfEmpty()
     where (a.Collected == false)
     select new
     {
         OrderId = a.OrderId,
         DeliveryBoyID = a.AssignTo,
         AssignedBoyName = b.Name,
         Assigndate = a.Assigndate,
         Collected = a.Collected,
         CollectedDate = a.CollectedDate,
         CollectionBagNo = a.CollectionBagNo,
         DeliverTo = e == null ? "Null" : e.Name,
         DeliverDate = a.DeliverDate,
         DeliverBagNo = a.DeliverBagNo,
         Delivered = a.Delivered

     });

-1

बाईं ओर जॉय के लिए सरल समाधान :

var setA = context.SetA;
var setB = context.SetB.Select(st=>st.Id).Distinct().ToList();
var leftOuter  = setA.Where(stA=> !setB.Contains(stA.Id)); 

नोट :

  • प्रदर्शन setb सुधार करने के लिए एक के लिए परिवर्तित किया जा सकता शब्दकोश (है कि अगर फिर से किया जाता है तो आप इस बदलना होगा: ! SetB.Contains (stA.Id) ) या एक HashSet
  • जब इसमें एक से अधिक क्षेत्र शामिल होते हैं, तो इसे सेट संचालन और लागू करने वाले एक वर्ग का उपयोग करके प्राप्त किया जा सकता है : IEqualityComparer

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