3 minute read

개요


LINQ(Language Integrated Query)는 데이터를 질의하고 조작하기 위해 일관되고, 직관된 문법으로 C# 언어에 통합된 쿼리 기능입니다.
데이터 소스(컬렉션, 데이터베이스, XML 등)에서 데이터를 효율적으로 검색, 필터링, 정렬, 그룹화하는 등의 작업을 수행할 수 있도록 해줍니다. LINQ를 사용하면 SQL과 유사한 구문으로 코드를 작성하여 데이터를 쉽게 조작할 수 있으며, 코드의 가독성과 유지 보수성을 향상시키는 데 도움이 됩니다.


특징


  • 통합된 쿼리: C# 언어 내에서 직접 쿼리를 작성할 수 있어 코드의 가독성이 높아집니다.
  • 다양한 데이터 소스 지원: 컬렉션(List, Array 등), 데이터베이스(Entity Framework 등), XML 등 다양한 데이터 소스에서 쿼리할 수 있습니다.
  • 표준 쿼리 연산자 제공: Where, Select, OrderBy, GroupBy 등 표준 쿼리 연산자를 사용하여 데이터를 조작할 수 있습니다.
  • 메서드 구문과 쿼리 구문: 메서드 체이닝 방식의 메서드 구문과 SQL과 유사한 쿼리 구문 두 가지 방식을 모두 사용할 수 있습니다.
  • 지연된 실행(Deferred Execution): 쿼리가 실제로 실행되는 시점을 지연시켜 성능을 향상시킬 수 있습니다.
  • 강력한 타입 안정성: 컴파일 시점에 쿼리의 오류를 검사하여 런타임 오류를 줄일 수 있습니다.

장단점


장점

  • 데이터 조작 코드를 간결하고 가독성 높게 작성할 수 있습니다.
  • 다양한 데이터 소스를 일관된 방식으로 처리할 수 있습니다.
  • 코드 생산성과 유지 보수성을 향상시킵니다.
  • 타입 안정성을 제공하여 오류를 사전에 방지할 수 있습니다.

단점

  • 처음에는 쿼리 구문이나 메서드 구문에 익숙해지는 데 시간이 걸릴 수 있습니다.
  • 복잡한 쿼리의 경우 성능 문제가 발생할 수 있으므로 최적화가 필요할 수 있습니다.
  • 지연된 실행으로 인해 디버깅이 다소 어려울 수 있습니다.



주의점


  • 네임스페이스 추가: LINQ를 사용하기 전에 using System.Linq; 네임스페이스를 추가해야 합니다.
  • 지연된 실행 이해: 쿼리가 언제 실행되는지 이해하고 있어야 성능 문제를 방지할 수 있습니다. ToList()나 ToArray() 등의 메서드를 사용하여 즉시 실행할 수 있습니다.
  • 성능 고려: 복잡한 쿼리는 성능에 영향을 줄 수 있으므로 인덱싱, 필터링 순서 등을 고려하여 최적화해야 합니다.
  • Null 처리: 데이터 소스에 null 값이 포함되어 있을 경우 NullReferenceException이 발생할 수 있으므로 null 체크를 수행해야 합니다.

메서드 구문과 쿼리 구문 비교


메서드 구문:

var evenNumbers = numbers.Where(n => n % 2 == 0).OrderBy(n => n);


쿼리 구문:

var evenNumbers = from n in numbers
                  where n % 2 == 0
                  orderby n
                  select n;

사용법


  1. 네임스페이스 추가: 스크립트 상단에 using System.Linq;를 추가합니다.
  2. 데이터 소스 준비: 쿼리할 데이터 소스(컬렉션, 배열 등)를 준비합니다.
  3. 쿼리 작성: 메서드 구문 또는 쿼리 구문을 사용하여 쿼리를 작성합니다



LINQ 식


[from] : 어떤 데이터에서 원하는 값을 추출할 것인지를 정합니다.

IEnumerable<Item> _items = from item in items select item;
foreach (var _item in _items) _item.Print();


[Where] : 조건을 만족하는 요소만 필터링합니다.

List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var evenNumbers = numbers.Where(n => n % 2 == 0); // 짝수만 필터링


[Select] : 요소를 변환합니다.

var squaredNumbers = numbers.Select(n => n * n); // 각 숫자를 제곱


[OrderBy] : 요소를 정렬합니다.

var sortedNumbers = numbers.OrderBy(n => n); // 오름차순 정렬


[GroupBy] : 요소를 그룹화합니다.

var groupedNumbers = numbers.GroupBy(n => n % 2); // 짝수/홀수로 그룹화


[FirstOrDefault] : 조건에 맞는 첫 번째 요소를 반환하고, 없으면 기본값을 반환합니다.

int firstNumberGreaterThan10 = numbers.FirstOrDefault(n => n > 10); // 10보다 큰 첫 번째 숫자 (없으면 0 반환)


LINQ 함수


[Reverse] : 내용물을 뒤집는다.(반전시킨다.)

_items = items.Reverse();


[Distince] : 중복 제거

_items = items4.Distinct();


[Except] : 차집합 items - items2

_items = items.Except(items2);


[Intersect] : 교집합 items ∩ items2

_items = items.Intersect(items2);


[Union] : 합집합 items ∪ items2

_items = items.Union(items2);


[Where]

  • 조건이 true인 값을 선택
  • 다른 조건 함수와 다르게 IEnumerable 타입 리턴
// Where : 조건이 true인 값을 선택
_items = items.Where(x => x.code > 1);


[All] : 모두 true -> true 반환

bool b = items.All(x => x.code > 0);
print(b);


[Any] : 하나라도 true -> true 반환

bool b = items.Any(x => x.code > 3);
print(b);


[Contains] : 특정 원소 포함 여부 반환

bool b = items.Contains(new Item(3, "banana"), new ItemComparer());
print(b);


[Select]

  • 값을 추출해 IEnumerable 타입 리턴
  • Array/List 등의 타입을 IEnumerable 타입으로 변환
  • new {}를 통한 익명 형식 적용 가능
IEnumerable<int> codes = items.Select(x => x.code);
foreach (int code in codes)
    print(code);
var _customItems = items.Select(x => new { Name = x.name, CodeAdd = x.code + 1 });
foreach (var _customItem in _customItems)
    print(_customItem);


[SelectMany] : 두 IEnumerable의 모든 조합을 만듬

int[] number = new int[] { 10, 20 };
string[] animals = new string[] { "cat", "dog", "donkey" };
var mix = number.SelectMany(num => animals, (n, a) => new { n, a });
foreach (var a in mix)
    print(a); 


[Skip] : 건너뛰고 인자 인덱스부터 시작

_items = items.Skip(2);


[SkipWhile]

  • 순서대로 정렬됐을 때, true일 동안 스킵
  • {1, 2, 3, 4}에서 3보다 작을 동안을 스킵, 3, 4만 나옴
    int[] number = new int[] { 10, 20 };
    string[] animals = new string[] { "cat", "dog", "donkey" };
    var mix = number.SelectMany(num => animals, (n, a) => new { n, a });
    foreach (var a in mix)
      print(a); 
    


[Take] : 앞에서 부터 개수만큼 가져오기

_items = items.Take(2);


[TakeWhile]

  • 순서대로 정렬됐을 때, true일 동안 가져오기
  • {1, 2, 3, 4}에서 3보다 작을 동안 가져오기, 1, 2만 나옴
    _items = items.OrderBy(x => x.code).TakeWhile(x => x.code < 3);
    



Top