c# - LINQ में बाएं बाहरी जॉइन




join (12)

Linq सी # // में बाएं बाहरी जुड़ें प्रदर्शन करें बाएं बाहरी जुड़ें प्रदर्शन करें

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/

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

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
                                        })

जहां जॉइनपेयर एक वर्ग है:

public class JoinPair { long leftId; long rightId; }

Necromancing।
यदि डेटाबेस संचालित 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()

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

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

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

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 सर्वर क्वेरी कनवर्ट करें " भी देखें।

इसके अलावा, यदि आप इसे लिंक-2-ऑब्जेक्ट्स (लिंक-2-एसक्यूएल के बजाए) में कर रहे हैं, तो आपको इसे पुराने तरीके से करना चाहिए (क्योंकि LINQ से 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
    }

);

इस example पर एक नज़र डालें। यह क्वेरी काम करनी चाहिए:

var leftFinal =
        from l in lefts
        join r in rights on l equals r.Left into lrs
        from lr in lrs.DefaultIfEmpty()
        select new { LeftId = l.Id, RightId = ((l.Key==r.Key) ? r.Id : 0 };

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

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));
    }
}

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

कैसे करें: बाएं बाहरी जुड़ें (सी # प्रोग्रामिंग गाइड)



तीन सारणीएं हैं: व्यक्तियों, स्कूलों और व्यक्तियों के स्कूल, जो व्यक्तियों को उनके द्वारा पढ़े जाने वाले स्कूलों से जोड़ते हैं। Id = 6 वाले व्यक्ति का संदर्भ तालिका व्यक्तियों / विद्यालयों में अनुपस्थित है। हालांकि आईडी = 6 वाला व्यक्ति परिणामस्वरूप लीफ-शामिल ग्रिड में प्रस्तुत किया जाता है।

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 से अधिक तालिकाओं में शामिल होने की आवश्यकता है तो यहां एक उदाहरण दिया गया है:

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()

रेफरी: https://.com/a/17142392/2343


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

इस मामले में यदि मैं इसे शामिल स्थिति में करता हूं तो मैं लौटाई गई पंक्तियों को कम करता हूं।

टर्नरी हालत का उपयोग किया जाता है (= 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);

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

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 बनाता है जो दाएं हाथ की प्रविष्टियों ('बी' में प्रविष्टियों) के लिए प्रभावी रूप से शून्य 'पंक्तियां' शामिल करता है।

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

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_value के लिए शून्य संदर्भ अपवाद के बिना b_value के गुणों की जांच करने की अनुमति देता है। ध्यान दें कि एक नामुमकिन डेटटाइम के लिए, 'डेटटाइम?) यानी' नाइटटेबल डेटटाइम 'का एक प्रकार' डिफ़ॉल्ट 'त्रुटि' के लिए विनिर्देश में शून्य के 'प्रकार' के रूप में निर्दिष्ट किया जाना चाहिए (यह उन प्रकारों पर भी लागू होगा जो मूल रूप से नहीं हैं 'शून्य, उदाहरण के लिए डबल, फ्लोट)।

आप उपर्युक्त वाक्यविन्यास को आसानी से चेन करके एकाधिक बाएं बाहरी जुड़ सकते हैं।


लैम्ब्डा अभिव्यक्ति का प्रयोग करना

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   
  })

बाएं बाहरी जॉइन के लिए सरल समाधान:

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

नोट्स :

  • प्रदर्शन को बेहतर बनाने के लिए सेटबी को एक शब्दकोश में परिवर्तित किया जा सकता है (यदि यह किया जाता है तो आपको इसे बदलना होगा :! SetB.Contains (stA.Id) ) या हैशसेट
  • जब एक से अधिक फ़ील्ड शामिल होते हैं तो यह सेट ऑपरेशंस और एक वर्ग का उपयोग करके प्राप्त किया जा सकता है: IEqualityComparer

(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

     });




join