LINQ 쿼리 처음 작성(Visual Basic)
쿼리는 데이터 소스에서 데이터를 검색하는 식입니다. 쿼리는 전용 쿼리 언어로 표현됩니다. 시간이 지남에 따라 관계형 데이터베이스용 SQL, XML용 XQuery 등 다양한 형식의 데이터 원본에 대해 다양한 언어가 개발되었습니다. 따라서 애플리케이션 개발자는 지원되는 데이터 원본 또는 데이터 형식의 각 형식에 대해 새로운 쿼리 언어를 배워야 합니다.
LINQ(Language-Integrated Query)는 다양한 종류의 데이터 원본 및 형식에 걸쳐 데이터 작업을 위한 일관된 모델을 제공하여 상황을 간소화합니다. LINQ 쿼리에서는 항상 개체를 사용합니다. 동일한 기본 코딩 패턴을 사용하여 XML 문서, SQL 데이터베이스, ADO.NET 데이터 세트 및 엔티티, .NET Framework 컬렉션, 기타 LINQ 공급자를 사용할 수 있는 모든 소스 또는 형식의 데이터를 쿼리하고 변환합니다. 이 문서에서는 기본 LINQ 쿼리를 만들고 사용하는 세 가지 단계에 대해 설명합니다.
쿼리 작업의 세 단계
LINQ 쿼리 작업은 다음 세 가지 작업으로 구성됩니다.
데이터 원본 또는 원본을 가져옵니다.
쿼리 만들기.
쿼리를 실행합니다.
LINQ에서 쿼리 실행은 쿼리를 만드는 것과는 별개입니다. 쿼리를 만드는 것만으로는 데이터를 검색하지 않습니다. 이 내용에 대해서는 이 항목의 뒷부분에서 자세히 설명합니다.
다음 예제에서는 쿼리 작업의 세 부분을 보여 줍니다. 이 예제에서는 보여 주기 위한 편리한 데이터 원본으로 정수 배열을 사용합니다. 그러나 다른 데이터 원본에도 동일한 개념이 적용됩니다.
참고 항목
컴파일 페이지의 프로젝트 디자이너(Visual Basic)에서 옵션 유추가 켜짐으로 설정되어 있는지 확인합니다.
' Data source.
Dim numbers() As Integer = {0, 1, 2, 3, 4, 5, 6}
' Query creation.
Dim evensQuery = From num In numbers
Where num Mod 2 = 0
Select num
' Query execution.
For Each number In evensQuery
Console.Write(number & " ")
Next
출력
0 2 4 6
데이터 소스
이전 예제의 데이터 원본은 배열이므로 제네릭 IEnumerable<T> 인터페이스를 암시적으로 지원합니다. 바로 이 사실 때문에 배열을 LINQ 쿼리의 데이터 원본으로 사용할 수 있습니다. IEnumerable<T> 또는 제네릭 IQueryable<T> 같은 파생된 인터페이스를 지원하는 형식을 쿼리 가능 형식이라고 합니다.
암시적으로 쿼리 가능한 형식인 배열은 LINQ 데이터 소스로 사용하기 위해 수정이나 특별한 처리가 필요하지 않습니다. 제네릭 List<T>, Dictionary<TKey,TValue>, .NET Framework 클래스 라이브러리의 기타 클래스를 포함하여 IEnumerable<T>을 지원하는 모든 컬렉션 형식의 경우에도 마찬가지입니다.
원본 데이터가 아직 IEnumerable<T>을 구현하지 않은 경우 해당 데이터 원본에 대한 표준 쿼리 연산자의 기능을 구현하려면 LINQ 공급자가 필요합니다. 예를 들어 다음 예제와 같이 LINQ to XML은 XML 문서를 쿼리 가능한 XElement 형식으로 로드하는 작업을 처리합니다. 표준 쿼리 연산자에 대한 자세한 내용은 표준 쿼리 연산자 개요(Visual Basic)를 참조하세요.
' Create a data source from an XML document.
Dim contacts = XElement.Load("c:\myContactList.xml")
먼저 LINQ to SQL을 사용하여 디자인 타임에 수동으로 또는 Visual Studio에서 Visual Studio의 LINQ to SQL 도구를 사용하여 개체 관계형 매핑을 만듭니다. 개체에 대한 쿼리를 작성하면 런타임에 LINQ to SQL에서 데이터베이스와의 통신을 처리합니다. 다음 예제에서 customers
는 데이터베이스의 특정 표를 나타내고 Table<TEntity>는 제네릭 IQueryable<T>을 지원합니다.
' Create a data source from a SQL table.
Dim db As New DataContext("C:\Northwind\Northwnd.mdf")
Dim customers As Table(Of Customer) = db.GetTable(Of Customer)
특정 형식의 데이터 소스를 만드는 방법에 대한 자세한 내용은 다양한 LINQ 공급자에 대한 설명서를 참조하세요. (이러한 공급자 목록은 LINQ(Language-Integrated Query)를 참조하세요.) 기본 규칙은 간단합니다. LINQ 데이터 소스는 제네릭 IEnumerable<T> 인터페이스 또는 이를 상속하는 인터페이스를 지원하는 모든 개체입니다.
참고 항목
제네릭이 아닌 IEnumerable 인터페이스를 지원하는 ArrayList과 같은 형식도 LINQ 데이터 소스로 사용할 수 있습니다. ArrayList를 사용하는 예는 방법: LINQ를 사용하여 ArrayList 쿼리(Visual Basic)를 참조하세요.
쿼리
쿼리에서 데이터 원본에서 검색하려는 정보를 지정합니다. 또한 정보가 반환되기 전에 해당 정보를 정렬, 그룹화 또는 구조화하는 방법을 지정할 수도 있습니다. 쿼리 만들기를 사용하도록 설정하기 위해 Visual Basic은 새로운 쿼리 구문을 언어에 통합했습니다.
이 쿼리가 실행되면 다음 예제의 쿼리는 정수 배열 numbers
에서 모든 짝수를 반환합니다.
' Data source.
Dim numbers() As Integer = {0, 1, 2, 3, 4, 5, 6}
' Query creation.
Dim evensQuery = From num In numbers
Where num Mod 2 = 0
Select num
' Query execution.
For Each number In evensQuery
Console.Write(number & " ")
Next
쿼리 식에는 From
, Where
, Select
의 세 가지 절이 포함되어 있습니다. 각 쿼리 식 절의 구체적인 기능과 목적은 기본 쿼리 작업(Visual Basic)에 설명되어 있습니다. 자세한 내용은 쿼리를 참조하세요. LINQ에서는 쿼리 정의가 변수에 저장되고 나중에 실행되는 경우가 많습니다. 이전 예제의 evensQuery
과 같은 쿼리 변수는 쿼리 가능 형식이어야 합니다. evensQuery
의 형식은 IEnumerable(Of Integer)
이며 컴파일러가 지역 형식 유추를 사용하여 할당합니다.
쿼리 변수 자체는 아무런 작업을 수행하지 않으며 데이터를 반환하지 않는다는 점을 기억하는 것이 중요합니다. 쿼리 변수는 쿼리 정의만 저장합니다. 이전 예제에서 쿼리를 실행하는 것은 For Each
루프입니다.
쿼리 실행
쿼리 실행은 쿼리 만들기와는 별개입니다. 쿼리 만들기는 쿼리를 정의하지만 실행은 다른 메커니즘에 의해 트리거됩니다. 쿼리를 정의한 후 곧바로 실행하거나(즉시 실행), 정의를 저장하고 나중에 쿼리를 실행할 수 있습니다(지연된 실행).
지연된 실행
일반적인 LINQ 쿼리는 evensQuery
가 정의된 이전 예제의 쿼리와 유사합니다. 쿼리를 만들지만 즉시 실행하지는 않습니다. 대신 쿼리 정의는 쿼리 변수 evensQuery
에 저장됩니다. 나중에 일반적으로 일련의 값을 반환하는 For Each
루프를 사용하거나 Count
또는 Max
와 같은 표준 쿼리 연산자를 적용하여 쿼리를 실행합니다. 이 프로세스를 지연된 실행이라고 합니다.
' Query execution that results in a sequence of values.
For Each number In evensQuery
Console.Write(number & " ")
Next
' Query execution that results in a single value.
Dim evens = evensQuery.Count()
값 시퀀스의 경우 For Each
루프(이전 예제에서는 number
)에서 반복 변수를 사용하여 검색된 데이터에 액세스합니다. 쿼리 변수 evensQuery
에는 쿼리 결과가 아닌 쿼리 정의가 저장되므로 쿼리 변수를 두 번 이상 사용하여 원하는 만큼 자주 쿼리를 실행할 수 있습니다. 예를 들어 애플리케이션에 별도의 애플리케이션에 의해 지속적으로 업데이트되는 데이터베이스가 있을 수 있습니다. 해당 데이터베이스에서 데이터를 검색하는 쿼리를 만든 후에는 For Each
루프를 사용하여 쿼리를 반복적으로 실행하여 매번 가장 최근 데이터를 검색할 수 있습니다.
다음 예제에서는 지연된 실행의 작동 방식을 보여 줍니다. evensQuery2
가 정의되고 For Each
루프로 실행된 후 이전 예제에서와 같이 데이터 원본 numbers
의 일부 요소가 변경됩니다. 그런 다음 두 번째 For Each
루프가 evensQuery2
를 다시 실행합니다. For Each
루프가 numbers
의 새 값을 사용하여 쿼리를 다시 실행하므로 두 번째 결과는 다릅니다.
Dim numberArray() = {0, 1, 2, 3, 4, 5, 6}
Dim evensQuery2 = From num In numberArray
Where num Mod 2 = 0
Select num
Console.WriteLine("Evens in original array:")
For Each number In evensQuery2
Console.Write(" " & number)
Next
Console.WriteLine()
' Change a few array elements.
numberArray(1) = 10
numberArray(4) = 22
numberArray(6) = 8
' Run the same query again.
Console.WriteLine(vbCrLf & "Evens in changed array:")
For Each number In evensQuery2
Console.Write(" " & number)
Next
Console.WriteLine()
출력
Evens in original array:
0 2 4 6
Evens in changed array:
0 10 2 22 8
즉시 실행
쿼리의 지연 실행에서 쿼리 정의는 나중에 실행하기 위해 쿼리 변수에 저장됩니다. 즉시 실행에서는 쿼리가 정의될 때 쿼리가 실행됩니다. 쿼리 결과의 개별 요소에 액세스해야 하는 메서드를 적용하면 실행이 트리거됩니다. 단일 값을 반환하는 표준 쿼리 연산자 중 하나를 사용하여 즉시 실행을 강제하는 경우가 많습니다. Count
, Max
, Average
, First
를 예로 들 수 있습니다. 이러한 표준 쿼리 연산자는 싱글톤 결과를 계산하고 반환하기 위해 쿼리가 적용되자마자 실행됩니다. 단일 값을 반환하는 표준 쿼리 연산자에 대한 자세한 내용은 집계 작업, 요소 작업, 수량자 작업을 참조하세요.
다음 쿼리는 정수 배열의 짝수 개수를 반환합니다. 쿼리 정의가 저장되지 않았으며 numEvens
은 단순한 Integer
입니다.
Dim numEvens = (From num In numbers
Where num Mod 2 = 0
Select num).Count()
Aggregate
메서드를 사용하여 동일한 결과를 얻을 수 있습니다.
Dim numEvensAgg = Aggregate num In numbers
Where num Mod 2 = 0
Select num
Into Count()
다음 코드와 같이 쿼리(즉시) 또는 쿼리 변수(지연)에서 ToList
또는 ToArray
메서드를 호출하여 쿼리를 강제로 실행할 수도 있습니다.
' Immediate execution.
Dim evensList = (From num In numbers
Where num Mod 2 = 0
Select num).ToList()
' Deferred execution.
Dim evensQuery3 = From num In numbers
Where num Mod 2 = 0
Select num
' . . .
Dim evensArray = evensQuery3.ToArray()
이전 예제에서 evensQuery3
은 쿼리 변수이지만 evensList
는 목록이고 evensArray
는 배열입니다.
ToList
또는 ToArray
를 사용하여 즉시 실행을 강제하는 것은 쿼리를 즉시 실행하고 결과를 단일 컬렉션 개체에 캐시하려는 시나리오에서 특히 유용합니다. 이러한 메서드에 대한 자세한 내용은 데이터 형식 변환을 참조하세요.
IEnumerable.GetEnumerator 메서드와 같은 IEnumerable
메서드를 사용하여 쿼리가 실행되도록 할 수도 있습니다.
참고 항목
.NET