Vì đây có vẻ là câu hỏi SO thực tế cho các phép nối ngoài trái bằng cách sử dụng cú pháp phương thức (phần mở rộng), tôi nghĩ rằng tôi sẽ thêm một câu trả lời cho câu trả lời hiện được chọn mà ít nhất là theo kinh nghiệm của tôi sau
// Option 1: Expecting either 0 or 1 matches from the "Right"
// table (Bars in this case):
var qry = Foos.GroupJoin(
Bars,
foo => foo.Foo_Id,
bar => bar.Foo_Id,
(f,bs) => new { Foo = f, Bar = bs.SingleOrDefault() });
// Option 2: Expecting either 0 or more matches from the "Right" table
// (courtesy of currently selected answer):
var qry = Foos.GroupJoin(
Bars,
foo => foo.Foo_Id,
bar => bar.Foo_Id,
(f,bs) => new { Foo = f, Bars = bs })
.SelectMany(
fooBars => fooBars.Bars.DefaultIfEmpty(),
(x,y) => new { Foo = x.Foo, Bar = y });
Để hiển thị sự khác biệt bằng cách sử dụng một tập dữ liệu đơn giản (giả sử chúng ta đang tham gia vào chính các giá trị):
List<int> tableA = new List<int> { 1, 2, 3 };
List<int?> tableB = new List<int?> { 3, 4, 5 };
// Result using both Option 1 and 2. Option 1 would be a better choice
// if we didn't expect multiple matches in tableB.
{ A = 1, B = null }
{ A = 2, B = null }
{ A = 3, B = 3 }
List<int> tableA = new List<int> { 1, 2, 3 };
List<int?> tableB = new List<int?> { 3, 3, 4 };
// Result using Option 1 would be that an exception gets thrown on
// SingleOrDefault(), but if we use FirstOrDefault() instead to illustrate:
{ A = 1, B = null }
{ A = 2, B = null }
{ A = 3, B = 3 } // Misleading, we had multiple matches.
// Which 3 should get selected (not arbitrarily the first)?.
// Result using Option 2:
{ A = 1, B = null }
{ A = 2, B = null }
{ A = 3, B = 3 }
{ A = 3, B = 3 }
Tùy chọn 2 đúng với định nghĩa nối ngoài bên trái điển hình, nhưng như tôi đã đề cập trước đó thường phức tạp không cần thiết tùy thuộc vào tập dữ liệu.
GroupJoin
không tham gia bên ngoài bên trái,SelectMany
phần chỉ cần thiết tùy thuộc vào những gì bạn muốn chọn.