나만의 작은 도서관

[C#] 문법 정리 #13. LINQ(Language Integrated Query) 본문

Unity/문법 및 메소드(System)

[C#] 문법 정리 #13. LINQ(Language Integrated Query)

pledge24 2024. 11. 25. 20:30

LINQ(Language Integrated Query)

LINQ는 .NET 프레임워크에서 제공되는 쿼리 언어 확장이며, 데이터 소스(컬렉션, 데이터베이스, XML 등)에 대한 쿼리를 C# 언어 자체에 통합한 강력한 기능이다. LINQ를 사용하면 다양한 데이터 소스에 대해 일관된 방식으로 쿼리를 작성하고 실행할 수 있다. (조금 뻔한 이야기지만, 로우 쿼리를 대체하는 대부분의 방법들이 그랬듯이 LINQ 또한 로우 쿼리보다 성능이 떨어지며, 복잡한 쿼리에선 로우 쿼리만큼 직관적이지 않을 수 있다.)

 

LINQ를 사용하는 이유

  • 통합된 쿼리 구문: SQL과 유사한 구문을 사용하여 데이터에 접근할 수 있다. (데이터 접근과 비즈니스 로직을 하나의 언어(C#)로 통합)
  • 코드 가독성 증가: 일관된 방식으로 쿼리를 작성하여 코드의 가독성이 올라간다.
  • 타입 안정성: 컴파일 시점에 쿼리의 타입을 검사하여 오류를 줄일 수 있다.
  • 편리한 변환 및 필터링: 데이터의 선택, 필터링, 정렬, 그룹화 등을 쉽게 수행한다.
  • 확장성: 객체, 데이터베이스, XML 문서 등 다양한 데이터 소스를 지원한다.

 

LINQ의 구성 요소

LINQ는 다양한 데이터 소스에서 사용할 수 있도록 설계되었다. 주요 LINQ 기술은 다음과 같다.

  • LINQ to Objects : 메모리에 있는 컬렉션(List, Array 등)을 대상으로 쿼리를 수행
  • LINQ to SQL:데이터베이스(SQL Server)를 대상으로 쿼리를 수행하며, SQL 명령으로 변환
  • LINQ to XML : XML 문서에 대한 쿼리를 제공
  • LINQ to Entities (Entity Framework) : 데이터베이스와 상호작용하는 ORM(Object-Relational Mapping) 도구를 제공

 

표준 쿼리 연산자

LINQ는 SQL과 유사한 구문을 사용한다. 그에 맞는 키워드도 추가되며 주요 키워드는 다음과 같다.

  • 필터링: Where
  • 정렬: OrderBy, OrderByDescending, ThenBy, ThenByDescending
  • 선택: Select, SelectMany
  • 집계: Count, Sum, Average, Min, Max
  • 그룹화: GroupBy
  • 조인: Join, GroupJoin
  • 페이징: Skip, Take
  • 집합 연산: Distinct, Union, Intersect, Except
  • 단일 요소 추출: First, FirstOrDefault, Single, SingleOrDefault, Last, LastOrDefault

 

 

기본 구조 예제

LINQ는 쿼리 구문(Query Syntax) 스타일과 메서드 구문(Method Syntax) 스타일 둘 다 지원한다.

// 쿼리 구문(Query Syntax): SQL과 유사한 선언적 스타일.
var result = from person in people
             where person.Age > 18
             orderby person.Name
             select person.Name;
          
// 메서드 구문(Method Syntax): 메서드 체이닝 방식으로, 확장 메서드를 사용하는 방식.
var result = people
             .Where(person => person.Age > 18)
             .OrderBy(person => person.Name)
             .Select(person => person.Name);

 

 

LINQ 주요 메서드 예제(LINQ to Objects)

List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// 필터링(WHERE절)
var filtered = numbers.Where(n => n > 5); // 6, 7, 8, 9, 10

// 정렬(ORDER BY)
var sorted = numbers.OrderBy(n => n); // 1, 2, 3, ...

// 선택(SELECT절)
var squared = numbers.Select(n => n * n); // 1, 4, 9, ...

// 집계
var count = numbers.Count(); // 10
var sum = numbers.Sum();     // 55
var average = numbers.Average(); // 5.5

// 조인(JOIN)
var result = from p in products
             join c in categories on p.CategoryId equals c.Id
             select new { p.Name, c.CategoryName };

 

 

지연 실행과 즉시 실행

LINQ 쿼리는 지연 실행(Deferred Execution)과 즉시 실행(Eager Execution)의 두 가지 실행 방식을 가진다. 지연 실행과 즉시 실행의 뜻은 다음과 같다.

  • 지연 실행(Deferred Execution): 쿼리가 정의된 시점에는 실행되지 않고, 결과가 실제로 필요할 때 실행. 대부분의 표준 쿼리 연산자는 지연 실행을 따른다.
  • 즉시 실행(Eager Execution): 쿼리가 정의되는 즉시 결과를 생성한다. ToList(), ToArray(), Count(), First() 등의 메서드가 즉시 실행을 수행한다.
// 지연 실행
var query = people.Where(p => p.Age > 18); // 실행되지 않음
foreach (var person in query) // 여기서 실행됨
{
    Console.WriteLine(person.Name);
}

// 즉시 실행 
var list = people.Where(p => p.Age > 18).ToList(); // 즉시 실행됨

 

 

 

확장 메서드

LINQ는 주로 확장 메서드를 통해 구현된다. 확장 메서드란 기존 타입에 새로운 메서드를 추가할 수 있게해주는 C#의 기능이다.

public static class Extensions
{
    // 성인인지 판별해주는 메서드
    public static bool IsAdult(this Person person)
    {
        return person.Age >= 18;
    }
}

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

var adults = people.Where(p => p.IsAdult()); // 메서드를 LINQ의 where절에 사용(확장 메서드)