서론
이전 포스트에서 LINQ의 기본 개념과 단일 데이터 원본에 대한 쿼리를 살펴봤습니다. 이번에는 LINQ의 더 강력한 기능들인 다중 데이터 원본 처리, 그룹화, 조인 연산에 대해 알아보고, LINQ의 내부 동작 원리까지 살펴보겠습니다.
본론
1. 여러 데이터 원본에 대한 쿼리
LINQ는 여러 데이터 원본을 동시에 다룰 수 있는 강력한 기능을 제공합니다. 이는 from 절을 중첩하여 구현합니다.
var query = from person in people
from skill in person.Skills
where skill.Level > 5
select new { person.Name, skill.Name, skill.Level };
C#
복사
중첩된 from 절을 사용하면 컬렉션의 컬렉션을 평탄화(flattening)하여 처리할 수 있습니다. 이는 데이터베이스의 교차 조인(cross join)과 유사한 결과를 제공합니다.
2. group by로 데이터 분류하기
데이터 분석에서 가장 중요한 작업 중 하나는 그룹화입니다. LINQ의 group by 절은 이를 효과적으로 지원합니다.
var query = from item in items
group item by item.Category into categoryGroup
select new {
Category = categoryGroup.Key,
Count = categoryGroup.Count(),
Average = categoryGroup.Average(item => item.Price)
};
C#
복사
그룹화의 결과는 IGrouping<TKey, TElement> 인터페이스를 구현하며, 다음과 같은 특징이 있습니다:
•
Key 속성으로 그룹화 기준에 접근 가능
•
IEnumerable<T>를 상속하여 그룹 내 요소들을 순회 가능
•
LINQ 집계 함수(Count, Sum, Average 등)와 함께 자주 사용됨
3. 데이터 원본 연결하기: join 연산
3.1 내부 조인 (Inner Join)
두 데이터 원본에서 매칭되는 데이터만 선택하는 연산입니다.
var query = from order in orders
join customer in customers
on order.CustomerId equals customer.Id
select new {
OrderId = order.Id,
CustomerName = customer.Name,
OrderDate = order.Date
};
C#
복사
3.2 외부 조인 (Outer Join)
LINQ는 왼쪽 외부 조인만 지원하며, DefaultIfEmpty() 메서드를 활용합니다.
var query = from customer in customers
join order in orders
on customer.Id equals order.CustomerId into orderGroup
from order in orderGroup.DefaultIfEmpty()
select new {
CustomerName = customer.Name,
OrderId = order?.Id ?? 0,
OrderDate = order?.Date ?? DateTime.MinValue
};
C#
복사
4. LINQ의 내부 동작 원리
LINQ의 우아한 쿼리 구문은 실제로는 메서드 호출로 변환됩니다. 예를 들어:
// 쿼리 구문
var query = from item in items
where item.Price > 1000
select item.Name;
// 컴파일러가 변환하는 메서드 구문
var query = items
.Where(item => item.Price > 1000)
.Select(item => item.Name);
C#
복사
이러한 변환은 C# 컴파일러에 의해 이루어지며, 이는 LINQ가 특별한 런타임 지원 없이도 동작할 수 있게 합니다.
4.1 LINQ 표준 연산자
LINQ는 53개의 표준 연산자 메서드를 제공하지만, 쿼리 구문으로는 11개만 직접 지원됩니다. 따라서 복잡한 쿼리를 작성할 때는 메서드 구문과 쿼리 구문을 적절히 조합하는 것이 효과적입니다.
var query = (from item in items
where item.Price > 1000
select item)
.Take(5) // 메서드 구문 활용
.OrderBy(x => x.Name);
C#
복사
결론
LINQ는 단순한 질의 도구를 넘어 데이터 처리의 강력한 추상화 계층을 제공합니다. 실제 개발 과정에서 LINQ를 효과적으로 활용하기 위해서는 쿼리식과 메서드 구문을 상황에 맞게 적절히 조합하는 것이 중요합니다.
참고 자료
•
박상현, "이것이 C#이다", 한빛미디어, 2023