Search

이것이 C#이다: 15장 - LINQ (2/2)

서론

이전 포스트에서 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