ฉันค้นเว็บแล้ว แต่ฉันยังหาคำตอบง่าย ๆ ไม่ได้ มีคนช่วยอธิบายด้วยภาษาอังกฤษง่ายๆGroupJoinได้ไหม? มันแตกต่างจากภายในทั่วไปJoinอย่างไร ใช้บ่อยไหม มันเป็นเพียงไวยากรณ์ของวิธีการ? สิ่งที่เกี่ยวกับไวยากรณ์แบบสอบถาม ตัวอย่างรหัส c # น่าจะดี
ฉันค้นเว็บแล้ว แต่ฉันยังหาคำตอบง่าย ๆ ไม่ได้ มีคนช่วยอธิบายด้วยภาษาอังกฤษง่ายๆGroupJoinได้ไหม? มันแตกต่างจากภายในทั่วไปJoinอย่างไร ใช้บ่อยไหม มันเป็นเพียงไวยากรณ์ของวิธีการ? สิ่งที่เกี่ยวกับไวยากรณ์แบบสอบถาม ตัวอย่างรหัส c # น่าจะดี
คำตอบ:
สมมติว่าคุณมีสองรายการ:
Id Value
1 A
2 B
3 C
Id ChildValue
1 a1
1 a2
1 a3
2 b1
2 b2
เมื่อคุณJoinทั้งสองรายการในIdสนามผลลัพธ์จะเป็น:
Value ChildValue
A a1
A a2
A a3
B b1
B b2
เมื่อคุณGroupJoinทั้งสองรายการในIdสนามผลลัพธ์จะเป็น:
Value ChildValues
A [a1, a2, a3]
B [b1, b2]
C []
ดังนั้นJoinสร้างผลลัพธ์แบบแบน (ตาราง) ของค่าหลักและค่ารอง
GroupJoinสร้างรายการของรายการในรายการแรกแต่ละรายการมีกลุ่มของรายการที่เข้าร่วมในรายการที่สอง
นั่นเป็นเหตุผลที่Joinเทียบเท่าของINNER JOINใน SQL: Cมีรายการไม่ while GroupJoinมีค่าเท่ากับOUTER JOIN: Cอยู่ในชุดผลลัพธ์ แต่มีรายการว่างของรายการที่เกี่ยวข้อง (ในชุดผลลัพธ์ SQL จะมีแถวC - null)
ดังนั้นให้ทั้งสองรายการเป็นIEnumerable<Parent>และIEnumerable<Child>ตามลำดับ (ในกรณีของการ Linq เพื่อองค์กร: IQueryable<T>)
Join ไวยากรณ์จะเป็น
from p in Parent
join c in Child on p.Id equals c.Id
select new { p.Value, c.ChildValue }
ส่งคืนIEnumerable<X>ที่ X เป็นประเภทที่ไม่ระบุชื่อที่มีสองคุณสมบัติและValue ChildValueไวยากรณ์เคียวรีนี้ใช้Joinเมธอดภายใต้ประทุน
GroupJoin ไวยากรณ์จะเป็น
from p in Parent
join c in Child on p.Id equals c.Id into g
select new { Parent = p, Children = g }
กลับโดยIEnumerable<Y>ที่ Y เป็นประเภทที่ไม่ระบุตัวตนประกอบด้วยคุณสมบัติประเภทหนึ่งParentและคุณสมบัติประเภทIEnumerable<Child>หนึ่ง ไวยากรณ์เคียวรีนี้ใช้GroupJoinเมธอดภายใต้ประทุน
เราสามารถทำได้select gในการสืบค้นหลังซึ่งจะเลือกรายการIEnumerable<IEnumerable<Child>>พูดรายการ ในหลายกรณีการเลือกที่มีพาเรนต์รวมอยู่จะมีประโยชน์มากกว่า
ดังที่กล่าวไว้คำสั่ง ...
from p in Parent
join c in Child on p.Id equals c.Id into g
select new { Parent = p, Children = g }
... สร้างรายชื่อผู้ปกครองที่มีกลุ่มลูก สิ่งนี้สามารถเปลี่ยนเป็นรายการแบบแบนของคู่พาเรนต์ - ชายโดยการเพิ่มขนาดเล็กสองรายการ:
from p in parents
join c in children on p.Id equals c.Id into g // <= into
from c in g.DefaultIfEmpty() // <= flattens the groups
select new { Parent = p.Value, Child = c?.ChildValue }
ผลลัพธ์จะคล้ายกับ
Value Child
A a1
A a2
A a3
B b1
B b2
C (null)
โปรดทราบว่าตัวแปรช่วง cจะถูกใช้ซ้ำในคำสั่งด้านบน การทำเช่นนี้joinคำสั่งใด ๆสามารถถูกแปลงเป็น a ได้outer joinโดยการเพิ่มคำสั่งที่เทียบเท่าinto g from c in g.DefaultIfEmpty()กับjoinคำสั่งที่มีอยู่
นี่คือที่การสืบค้น (หรือครอบคลุม) ไวยากรณ์ส่อง ไวยากรณ์ของเมธอด (หรือคล่องแคล่ว) แสดงให้เห็นว่าเกิดอะไรขึ้นจริง แต่ยากที่จะเขียน:
parents.GroupJoin(children, p => p.Id, c => c.Id, (p, c) => new { p, c })
.SelectMany(x => x.c.DefaultIfEmpty(), (x,c) => new { x.p.Value, c?.ChildValue } )
ดังนั้นแบนouter joinใน LINQ เป็นแบนโดยGroupJoinSelectMany
สมมติว่ารายชื่อผู้ปกครองนั้นมีความยาวขึ้นอีกเล็กน้อย UI บางรายการสร้างรายการของพาเรนต์ที่เลือกเป็นIdค่าในลำดับคงที่ มาใช้กัน:
var ids = new[] { 3,7,2,4 };
ตอนนี้ผู้ปกครองที่เลือกจะต้องถูกกรองออกจากรายการผู้ปกครองในลำดับที่แน่นอนนี้
ถ้าเราทำ ...
var result = parents.Where(p => ids.Contains(p.Id));
... ลำดับของparentsจะเป็นตัวกำหนดผลลัพธ์ หากผู้ปกครองได้รับคำสั่งIdผลที่ได้คือผู้ปกครอง 2, 3, 4, 7 ไม่ดี อย่างไรก็ตามเรายังสามารถใช้joinในการกรองรายการ และโดยใช้idsเป็นรายการแรกคำสั่งซื้อจะถูกเก็บไว้:
from id in ids
join p in parents on id equals p.Id
select p
ผลลัพธ์คือผู้ปกครอง 3, 7, 2, 4
ตามeduLINQ :
วิธีที่ดีที่สุดในการเข้าถึงสิ่งที่ GroupJoin ทำคือคิดถึงการเข้าร่วม ที่นั่นแนวคิดโดยรวมคือเรามองผ่านลำดับการป้อนข้อมูล "ด้านนอก" พบรายการที่ตรงกันทั้งหมดจากลำดับ "ภายใน" (ขึ้นอยู่กับการคาดการณ์ที่สำคัญในแต่ละลำดับ) จากนั้นให้คู่ขององค์ประกอบการจับคู่ GroupJoin คล้ายยกเว้นว่าแทนที่จะยอมคู่ขององค์ประกอบก็มีผลเป็นผลเดี่ยวสำหรับแต่ละรายการ "นอก" ขึ้นอยู่กับสินค้าที่และลำดับของการจับคู่รายการ
ความแตกต่างเพียงอย่างเดียวคือข้อความสั่งคืน:
เข้าร่วม :
var lookup = inner.ToLookup(innerKeySelector, comparer);
foreach (var outerElement in outer)
{
var key = outerKeySelector(outerElement);
foreach (var innerElement in lookup[key])
{
yield return resultSelector(outerElement, innerElement);
}
}
กลุ่มงาน :
var lookup = inner.ToLookup(innerKeySelector, comparer);
foreach (var outerElement in outer)
{
var key = outerKeySelector(outerElement);
yield return resultSelector(outerElement, lookup[key]);
}
อ่านเพิ่มเติมได้ที่นี่: