300x250
지난 편에서는 LINQ Join()
을 정리했었다.
이번엔 그 연장선으로 GroupJoin()을 다뤄보려고 한다.
한 줄 요약하면 “1:N 관계 조인할 때 쓰는 Join”이다.

📚 목차
1. GroupJoin이란?
GroupJoin()
은 한 항목(1개)에 여러 항목(N개)이 연결되는 구조일 때 사용한다.
예: 고객 1명이 여러 주문을 할 수 있을 때 = 고객 : 주문 = 1 : N
구조는 이렇게 생겼다:
var 결과 = 컬렉션1.GroupJoin(
컬렉션2,
x => x.기준값,
y => y.기준값,
(x, y목록) => 새로운형태
);
x
: 기준이 되는 항목 (1)y목록
: 매칭되는 항목들의 목록 (N)
2. 실전 예제: 고객 + 주문
고객 1명에 여러 주문이 연결된 예제다.
var customers = new List<Customer>
{
new Customer { Id = 1, Name = "홍길동" },
new Customer { Id = 2, Name = "김영희" },
new Customer { Id = 3, Name = "이철수" }
};
var orders = new List<Order>
{
new Order { Id = 101, CustomerId = 1, Product = "노트북" },
new Order { Id = 102, CustomerId = 1, Product = "마우스" },
new Order { Id = 103, CustomerId = 2, Product = "키보드" }
};
var result = customers.GroupJoin(
orders,
c => c.Id,
o => o.CustomerId,
(c, orderList) => new { c.Name, Orders = orderList }
);
foreach (var item in result)
{
Console.WriteLine($"{item.Name}님의 주문 목록:");
foreach (var order in item.Orders)
{
Console.WriteLine($" - {order.Product}");
}
}
홍길동님의 주문 목록:
- 노트북
- 마우스
김영희님의 주문 목록:
- 키보드
이철수님의 주문 목록:
→ 주문이 없는 이철수도 결과엔 포함됨. 이게 GroupJoin의 장점이다.
3. SelectMany로 펼치기 (평탄화)
방금 결과는 IEnumerable<IEnumerable<>>
구조라 출력이 중첩된다.
한 줄로 펴고 싶을 때는 SelectMany()
를 쓴다.
var flattened = customers.GroupJoin(
orders,
c => c.Id,
o => o.CustomerId,
(c, os) => new { c.Name, Orders = os.DefaultIfEmpty() }
)
.SelectMany(
x => x.Orders,
(c, o) => new { c.Name, Product = o?.Product ?? "주문 없음" }
);
foreach (var item in flattened)
{
Console.WriteLine($"{item.Name} - {item.Product}");
}
홍길동 - 노트북
홍길동 - 마우스
김영희 - 키보드
이철수 - 주문 없음
→ DefaultIfEmpty()
로 null 처리도 가능하다.
4. 오류 예시 & 해결법
❌ 문제 1: null 참조 오류
foreach (var order in item.Orders)
{
Console.WriteLine(order.Product); // order가 null이면 에러
}
→ 주문이 없는 경우 order
가 null이 될 수 있다.
System.NullReferenceException: 'Object reference not set to an instance of an object.'
✅ 해결법:
Console.WriteLine(order?.Product ?? "주문 없음");
❌ 문제 2: GroupJoin 했는데 결과가 없음
→ 키 값 타입이 다르면 매칭 안 된다.
Customer.Id = int, Order.CustomerId = string → 실패
✅ 해결법: 타입 맞춰주기
orders.Select(o => new Order {
Id = o.Id,
CustomerId = int.Parse(o.CustomerId),
Product = o.Product
});
5. 마무리
GroupJoin은 1:N 관계에서 진가를 발휘하는 LINQ 기능이다.
- 중첩 결과가 기본이라
SelectMany()
로 평탄화 필요 - null 오류는 거의 항상 따라오니
?.
,??
필수 - 타입 mismatch는 눈치 못 챘다가 데이터가 안 나오는 원인 1위
다음 편에서는 Join vs GroupJoin을 비교하면서, 언제 어떤 걸 써야 할지 정리해보려 한다 😎
300x250