| 설계자 | 마이크로소프트 |
|---|---|
| 개발자 | 마이크로소프트 |
| 자료형 체계 | 스트롱 타입(Strongly typed) |
| 웹사이트 | docs |
| 주요 구현체 | |
| 닷넷 언어 (C#, F#, 비주얼 베이직 닷넷) | |
| 영향을 받은 언어 | |
| SQL, 하스켈 | |
LINQ('링크'로 발음, Language Integrated Query)는 네이티브 데이터 질의 기능을 닷넷 언어에 추가하는 마이크로소프트 닷넷 프레임워크 구성 요소이며 2007년 닷넷 프레임워크 3.5의 중요 부분으로 처음 출시되었다.
LINQ는 SQL 문과 비슷하게 질의식의 추가를 통해 언어를 확장하며 배열, 열거식 클래스, XML 도큐먼트, 관계형 데이터베이스, 서드파티 데이터 소스로부터 데이터를 편리하게 추출하고 가공하기 위해 사용할 수 있다. 질의식을 임의의 계산을 읽기 쉽게 구성하기 위한 일반적인 프레임워크로 활용하는 다른 용례로는 이벤트 핸들러 구성, 모나딕 파서가 포함된다.
LINQ의 포팅판으로는 PHP(PHPLinq 보관됨 2018-01-19 - 웨이백 머신), 자바스크립트(linq.js), 타입스크립트(linq.ts), 액션스크립트(ActionLinq)용으로 존재하지만 이 중 어느 것도 닷넷 파생 언어 C#, F#, VB.NET과 완전히 동일한 것은 아니다.
다음은 컬렉션으로 작업하는 애플리케이션에 기반한 연산자 설명이다. 많은 연산자가 다른 함수를 인수로 받는다. 이 함수들은 이름 있는 메서드나 익명 함수 형태로 제공될 수 있다.
LINQ에서 정의한 쿼리 연산자 집합은 표준 쿼리 연산자(SQO) API로 사용자에게 노출된다. API가 지원하는 쿼리 연산자는 다음과 같다:
이 연산자들은 선택적으로 컬렉션의 각 요소에서 특정 숫자 값을 검색하고 이를 사용하여 컬렉션의 모든 요소에 대한 합계, 최소값, 최대값 또는 평균값을 각각 찾는 함수를 받는다. 오버로드된 버전은 함수를 받지 않으며 람다로 항등 함수가 주어진 것처럼 동작한다.
일반화된 Sum / Min / Max. 이 연산자는 두 값을 결합하여 중간 결과 또는 최종 결과를 형성하는 방법을 지정하는 함수를 받는다. 선택적으로 시작 값을 제공할 수 있어 집계 결과의 유형을 임의로 지정할 수 있다. 또한 집계 결과를 또 다른 값으로 변환하는 최종화 함수를 제공할 수 있다. 이는 Fold 고차 함수를 구현한다.
IGrouping<Key, Values> 객체 컬렉션을 반환한다. IGrouping 객체는 특정 키 값에 대한 모든 객체를 열거하는 데 사용될 수 있다.표준 쿼리 연산자 API는 또한 컬렉션을 다른 유형으로 변환하는 특정 연산자를 지정한다:
IEnumerable<T>로 정적으로 형변환한다.IQueryable<T>로 정적으로 형변환한다.T[]를 생성한다.List<T>를 생성한다.Dictionary<K, T>를 생성한다. 사용자 제공 프로젝션 함수가 각 요소에서 키를 추출한다.Lookup<K, T>를 생성한다. 사용자 제공 프로젝션 함수가 각 요소에서 키를 추출한다.IEnumerable 컬렉션을 각 요소를 타입 T로 캐스팅하여 IEnumerable<T> 중 하나로 변환한다. 또는 각 요소를 타입 T에서 타입 R로 캐스팅하여 제네릭 IEnumerable<T>를 다른 제네릭 IEnumerable<R>로 변환한다. 어떤 요소라도 지정된 타입으로 캐스팅할 수 없으면 예외를 던진다.IEnumerable 컬렉션을 IEnumerable<T> 중 하나로 변환한다. 또는 각 요소를 타입 T에서 타입 R로 캐스팅을 시도하여 제네릭 IEnumerable<T>를 다른 제네릭 IEnumerable<R>로 변환한다. 두 경우 모두, 대상 타입으로 성공적으로 캐스팅된 요소의 하위 집합만 포함된다. 예외는 발생하지 않는다.LINQ는 주로 .NET Framework 3.5용 라이브러리로 구현되지만, 쿼리를 일급 언어 구성체로 만들고 쿼리 작성에 신택틱 슈거를 제공하는 선택적 언어 확장도 정의한다. 이러한 언어 확장은 처음에 C# 3.0,: 75 VB 9.0, F# 및 옥시즌에 구현되었으며, Nemerle와 같은 다른 언어들도 예비 지원을 발표했다. 언어 확장에는 다음이 포함된다:
var 키워드로 이를 선언한다. VB9.0에서는 타입 선언 없는 Dim 키워드가 동일한 기능을 수행한다. 이러한 객체는 여전히 강하게 타입이 지정된다. 이러한 객체에 대해 컴파일러는 자료형 추론을 통해 변수의 타입을 추론하며, 이는 중간 변수의 타입을 선언하지 않고도 쿼리 결과를 지정하고 정의할 수 있도록 한다.예를 들어, SomeProperty가 10 미만인 컬렉션의 모든 객체를 선택하는 쿼리에서,
IEnumerable<MyObject> SomeCollection = /* 여기에 뭔가 */
IEnumerable<MyObject> results = from c in SomeCollection
where c.SomeProperty < 10
select new {c.SomeProperty, c.OtherProperty};
foreach (MyObject result in results)
{
Console.WriteLine(result);
}
변수 result, c 및 results의 타입은 최종적으로 사용되는 메서드의 서명에 따라 컴파일러가 모두 추론한다. 메서드 선택의 기초는 쿼리 표현식이 없는 변환 결과에서 형성된다.
IEnumerble<MyObject> results =
SomeCollection
.Where(c => c.SomeProperty < 10)
.Select(c => new {c.SomeProperty, c.OtherProperty});
results.ForEach(x => {Console.WriteLine(x.ToString());})
C#3.0 사양은 쿼리 표현식 패턴과 LINQ 표현식에서 LINQ 표현식이 없는 C# 3.0의 하위 집합으로의 변환 규칙을 정의한다. 이렇게 정의된 변환은 실제로 타입이 지정되지 않으며, 람다 표현식이 델리게이트 또는 표현식 트리로 해석될 수 있다는 점과 더불어, 인터페이스의 일부를 LINQ 표현식 절로 노출하려는 라이브러리에 상당한 유연성을 제공한다. 예를 들어, LINQ to Objects는 IEnumerable<T> 및 델리게이트와 함께 작동하는 반면, LINQ to SQL은 표현식 트리를 사용한다.
표현식 트리는 LINQ 확장성 메커니즘의 핵심이며, 이를 통해 LINQ는 여러 데이터 소스에 맞게 조정될 수 있다. 표현식 트리는 LINQ 공급자에게 전달되며, 이들은 LINQ 쿼리를 데이터 소스에서 사용하도록 조정하는 데이터 소스별 구현이다. LINQ 공급자는 원하는 경우 쿼리에 포함된 표현식 트리를 분석하여 쿼리 실행에 필요한 필수 요소를 생성한다. 이는 SQL 조각이거나 추가로 조작 가능한 데이터로서 완전히 다른 코드 표현일 수 있다. LINQ는 인메모리 객체 컬렉션, 마이크로소프트 SQL 서버 데이터베이스, ADO.NET 데이터셋 및 XML 문서용 LINQ 공급자와 함께 제공된다. 이러한 다양한 공급자는 LINQ의 다양한 특징을 정의한다.
LINQ to Objects 공급자는 LINQ의 로컬 쿼리 실행 엔진을 사용하여 인메모리 컬렉션에 사용된다. 이 공급자가 생성하는 코드는 Sequence 패턴에 정의된 표준 쿼리 연산자 구현을 참조하며, IEnumerable<T> 컬렉션을 로컬에서 쿼리할 수 있도록 한다. LINQ to Objects의 현재 구현은 IEnumerable의 런타임 타입이 지원하는 경우 빠른 멤버십 테스트, 카운트 및 인덱스 조회 작업을 허용하기 위해 인터페이스 구현 검사를 수행한다.
LINQ to XML 공급자는 XML 문서를 XElement 객체 컬렉션으로 변환하며, 이 객체들은 표준 쿼리 연산자 구현의 일부로 제공되는 로컬 실행 엔진을 사용하여 쿼리된다.
LINQ to SQL 공급자는 SQL 서버 컴팩트 데이터베이스를 포함한 마이크로소프트 SQL 서버 데이터베이스를 쿼리하는 데 LINQ를 사용할 수 있도록 한다. SQL Server 데이터는 원격 서버에 있을 수 있고, SQL Server는 자체 쿼리 엔진을 가지고 있기 때문에, LINQ to SQL은 LINQ의 쿼리 엔진을 사용하지 않는다. 대신 LINQ 쿼리를 SQL 쿼리로 변환하여 처리하기 위해 SQL Server로 보낸다. 그러나 SQL Server는 데이터를 관계형 데이터로 저장하고 LINQ는 객체에 캡슐화된 데이터와 함께 작동하므로, 두 표현은 서로 매핑되어야 한다. 이러한 이유로 LINQ to SQL은 매핑 프레임워크도 정의한다. 매핑은 데이터베이스의 테이블에 해당하는 클래스를 정의하고, 테이블의 모든 또는 일부 열을 데이터 멤버로 포함하여 수행된다. 기본 키와 같은 다른 관계형 모델 속성과의 대응 관계는 LINQ to SQL이 정의한 특성을 사용하여 지정된다. 예를 들어,
[Table(Name="Customers")]
public class Customer
{
[Column(IsPrimaryKey = true)]
public int CustID;
[Column]
public string CustName;
}
이 클래스 정의는 Customers라는 이름의 테이블에 매핑되며, 두 데이터 멤버는 두 열에 해당한다. LINQ to SQL을 사용하기 전에 클래스를 정의해야 한다. 비주얼 스튜디오 2008에는 객체 및 관계형 도메인의 데이터 스키마 간 매핑을 생성하는 데 사용할 수 있는 매핑 디자이너가 포함되어 있다. 이 디자이너는 데이터베이스 스키마에서 해당 클래스를 자동으로 생성할 수 있을 뿐만 아니라, 테이블의 일부 테이블 또는 열만 사용하여 다른 뷰를 생성하기 위한 수동 편집도 허용한다.
매핑은 서버에 대한 연결 문자열을 받고 데이터베이스 테이블이 매핑될 타입인 T를 가진 Table<T>를 생성하는 데 사용될 수 있는 DataContext에 의해 구현된다. Table<T>는 테이블의 데이터를 캡슐화하고 IQueryable<T> 인터페이스를 구현하여, LINQ to SQL 공급자가 처리하는 표현식 트리가 생성된다. 이는 쿼리를 T-SQL로 변환하고 데이터베이스 서버에서 결과 집합을 검색한다. 처리는 데이터베이스 서버에서 발생하므로, 조건자를 나타내는 람다 표현식의 일부로 정의되지 않은 로컬 메서드는 사용할 수 없다. 그러나 서버의 저장 프로시저를 사용할 수 있다. 결과 집합에 대한 모든 변경 사항은 추적되며 데이터베이스 서버로 다시 제출될 수 있다.
위의 LINQ to SQL 공급자는 마이크로소프트 SQL 서버 데이터베이스에서만 작동하므로, 모든 일반 데이터베이스를 지원하기 위해 LINQ에는 LINQ to DataSets도 포함되어 있다. 이는 ADO.NET을 사용하여 데이터베이스와의 통신을 처리한다. 데이터가 ADO.NET 데이터셋에 들어가면, LINQ to DataSets는 이 데이터셋에 대해 쿼리를 실행한다.
닷넷 프레임워크 버전 4에는 PLINQ(Parallel LINQ)가 포함되어 있으며 이는 LINQ 쿼리들을 위한 병렬 실행 엔진이다. ParallelQuery<T> 클래스를 정의한다. IEnumerable<T> 인터페이스 구현체는 닷넷 프레임워크의 System.Linq 이름공간의 ParallelEnumerable 클래스에 의해 정의된 AsParallel<T>(this IEnumerable<T>) 확장 메소드를 호출함으로써 PLIQ 엔진의 이점을 활용할 수 있다. PLIQ 엔진은 다중 스레드로 동시에 쿼리의 일부를 실행할 수 있어서 더 빠른 결과를 도출해 낸다.