LINQ 개념
C# 3.0 이후 LINQ(Language Integrated Query, LINQ)는 데이터의 소스의 종류에 관계 없이 데이터를 조회(Query)하고 조작할 수 있도록 통합된 프로그래밍 모델을 제공한다.
| 구분 | 설명 |
|---|---|
| 정의 | C# 언어에 통합된 질의 기능 |
| 목적 | 데이터 소스마다 다른 질의 언어 대신, 단일 C# 구문으로 질의 작성 |
| 핵심 | 일관성, 타입 안정성, 가독성 |
LINQ 구문 형식
LINQ 쿼리는 SQL 문과 유사한 쿼리 구문과 메소드 호출을 사용하는 메소드 구문 두 가지 형태로 작성될 수 있다.
- 쿼리 구문: SQL 문에 익숙한 개발자에게 가독성이 높다. 보통 from 절로 시작하여 select 또는 group by 절로 끝난다.
// 데이터 소스
List<int> numbers = new List<int> { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
// 쿼리 구문 예제
var evenNumbers = from n in numbers
where n % 2 == 0 // 조건 필터링
orderby n ascending // 정렬
select n; // 결과 선택
// { 0, 2, 4, 6, 8 }
- 메소드 구문(람다 표현식 사용): 메소드 체이닝 방식을 사용하며, 쿼리 구문으로는 표현할 수 없는 복잡한 작업이나 쿼리 구문이 지원하지 않는 연산에 필수적이다.
// 메소드 구문 예제(위 쿼리 구문과 동일 기능)
var evenNumbersMethod = numbers.Where(n => n % 2 == 0)
.OrderBy(n => n)
.Select(n => n);
// { 0, 2, 4, 6, 8 }
LINQ 구성 요소
LINQ는 데이터를 처리하는 방식에 따라 크게 두 가지 종류로 나뉜다.
| 공급자 | 설명 | 데이터 소스 | 처리 방식 |
|---|---|---|---|
| LINQ to Objects | 메모리 내의 IEnumerable<T> 컬렉션 조회 |
Array, List<T>, Dictionary<T> 등 |
로컬 메모리에서 직접 실행 |
| LINQ to Entities(SQL) | 데이터베이스 조회 | SQL Server, PostgreSQL 등 | LINQ 쿼리가 데이터베이스가 이해하는 SQL 구문으로 변환되에 서버에서 실행된다. |
| LINQ to XML | XML 문서를 조회 및 조직 | XElement, XDocument |
LINQ 연산자
LINQ 연산자는 쿼리 구문의 절 또는 메소드 구문의 확장 메소드 형태로 제공된다.
| 범주 | 연산자(쿼리 구문 절) | 연산자(메소드 구문) | 기능 |
|---|---|---|---|
| 필터링 | where | Where() | 조건에 맞는 요소만 선택한다. |
| 프로젝션 | select | Select() | 각 요소에서 원하는 속성만 추출하거나 새로운 형태로 변환한다. |
| 정렬 | orderby | OrderBy(), OrderByDescending() | 결과를 오름차순 또는 내림차순으로 정렬한다. |
| 그룹화 | group by | GroupBy() | 공통된 키를 기준으로 요소를 그룹으로 묶는다. |
| 집합 | 없음 | Distinct(), Union(), Intersect(), Except() | 집합 연산(중복 제거, 합집합, 교집합 등)을 수행한다. |
| 요소 | 없음 | First(), Single(), Last(), ElementAt() | 특정 위치의 요소를 반환한다. |
| 집계 | 없음 | Count(), Sum(), Average(), Min(), Max() | 컬렉션 전체에 대한 통계 값을 계산한다. |
| 조인 | join | Join(), GroupJoin() | 두 컬렉션의 요소를 지정된 키를 기준으로 연결한다. |
LINQ 특징
LINQ의 실행에 대한 특징은 다음과 같다.
-
지연 실행(Deferred Execution): 대부분의 표준 쿼리 연산자는 즉시 실행되지 않는다. 대신 쿼리를 생성만 해두고, 결과가 실제로 필요할 때 실행된다. 이는 불필요한 연산을 방지하고, 쿼리가 최적화될 시간을 제공한다.
-
즉시 실행(Immediate Execution): 다음과 같은 연산자들은 쿼리 결과를 즉시 계산하여 반환한다.
-
집계 함수: Count(), Sum(), Average(), Min(), Max()
-
변환 함수: ToList(), ToArray(), ToDictionary()
-
요소 함수: First(), Single(), ElementAt()
-
지연 실행과 즉시 실행의 예제 코드는 다음과 같다.
// 지연 실행(쿼리가 정의될 때 실행되지 않는다.)
var deferredQuery = numbers.Where(n => n > 5);
// 즉시 실행(ToList()가 호출되는 시점에 쿼리를 실행한다.)
List<int> immediateResult = numbers.Where(n => n > 5).ToList();
고급 기능
LINQ의 세부 기능은 다음과 같다.
- 무명 형식: select 절에서 새로운 타입을 정의할 때 유용하며, 명시적인 클래스 정의 없이 필요한 속성만 담는 임시 컨테이너를 생성한다.
// 이름과 길이만 포함하는 무명 형식 생성
var shortNames = names.Select(n => new { Name = n, Length = n.Length });
- let 절: 쿼리 내에서 새로운 변수를 정의하고 저장하여, 복잡한 계산이나 중간 결과를 저장하여 쿼리 가독성을 높인다.
var query = from person in people
let fullName = person.FirstName + " " + person.LastName
where fullName.Length > 10
select fullName;