다음을 통해 공유


연습: C#에서 쿼리 작성(LINQ)

이 연습에서는 LINQ 쿼리 식을 작성하는 데 사용되는 C# 언어 기능을 보여 줍니다. 이 연습을 마치고 나면 LINQ to SQL, LINQ to DataSet 또는 LINQ to XML과 같은 원하는 특정 LINQ 공급자에 대한 샘플과 설명서를 진행할 수 있습니다.

사전 요구 사항

이 연습에서는 Visual Studio 2008에 도입 된 기능이 필요 합니다.

비디오에 링크 이 항목의 비디오 버전을 보려면 Video How to: Writing Queries in C# (LINQ)을 참조하십시오.

C# 프로젝트 만들기

프로젝트를 만들려면

  1. Visual Studio를 시작합니다.

  2. 메뉴 모음에서 파일, 새로 만들기, 프로젝트를 선택합니다.

    새 프로젝트 대화 상자가 열립니다.

  3. 확장 설치 된, 확장 템플릿, 확장 C#, 다음을 선택 하 고 콘솔 응용 프로그램.

  4. 이름 텍스트 상자 다른 이름을 입력 하거나 기본 이름을 적용 및 다음 선택은 확인 단추.

    솔루션 탐색기에 새 프로젝트가 나타납니다.

  5. 프로젝트에는 System.Core.dll에 대한 참조 및 System.Linq 네임스페이스에 대한 using 지시문이 있습니다.

메모리 내 데이터 소스 만들기

쿼리의 데이터 소스는 간단한 Student 개체 목록입니다. 각 Student 레코드는 이름, 성 및 클래스에서의 테스트 점수를 나타내는 정수 배열을 포함합니다. 프로젝트에 이 코드를 복사합니다. 다음 특성에 주의합니다.

  • Student 클래스는 자동 구현된 속성으로 구성됩니다.

  • 목록의 각 학생은 개체 이니셜라이저를 사용하여 초기화됩니다.

  • 목록 자체는 컬렉션 이니셜라이저를 사용하여 초기화됩니다.

이 전체 데이터 구조는 명시적 멤버 액세스나 생성자에 대한 명시적 호출 없이 초기화 및 인스턴스화됩니다. 이러한 새로운 기능에 대한 자세한 내용은 자동으로 구현된 속성(C# 프로그래밍 가이드)개체 및 컬렉션 이니셜라이저(C# 프로그래밍 가이드)를 참조하십시오.

데이터 소스를 추가하려면

  • Student 클래스와 학생의 초기화된 목록을 프로젝트의 Program 클래스에 추가합니다.

    public class Student
    {
        public string First { get; set; }
        public string Last { get; set; }
        public int ID { get; set; }
        public List<int> Scores;
    }
    
    // Create a data source by using a collection initializer. 
    static List<Student> students = new List<Student>
    {
       new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 92, 81, 60}},
       new Student {First="Claire", Last="O'Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}},
       new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int> {88, 94, 65, 91}},
       new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {97, 89, 85, 82}},
       new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {35, 72, 91, 70}},
       new Student {First="Fadi", Last="Fakhouri", ID=116, Scores= new List<int> {99, 86, 90, 94}},
       new Student {First="Hanying", Last="Feng", ID=117, Scores= new List<int> {93, 92, 80, 87}},
       new Student {First="Hugo", Last="Garcia", ID=118, Scores= new List<int> {92, 90, 83, 78}},
       new Student {First="Lance", Last="Tucker", ID=119, Scores= new List<int> {68, 79, 88, 92}},
       new Student {First="Terry", Last="Adams", ID=120, Scores= new List<int> {99, 82, 81, 79}},
       new Student {First="Eugene", Last="Zabokritski", ID=121, Scores= new List<int> {96, 85, 91, 60}},
       new Student {First="Michael", Last="Tucker", ID=122, Scores= new List<int> {94, 92, 91, 91} }
    };
    

새 학생을 학생 목록에 추가하려면

  • 새 Student를 Students 목록에 추가하고 원하는 이름과 테스트 점수를 사용합니다. 개체 이니셜라이저의 구문을 더 잘 배울 수 있도록 새 학생 정보를 모두 직접 입력해 봅니다.

쿼리 만들기

단순 쿼리를 만들려면

  • 응용 프로그램의 Main 메서드에서 첫 번째 테스트의 점수가 90점을 넘는 모든 학생의 목록을 실행 시에 생성하는 간단한 쿼리를 만듭니다. 전체 Student 개체가 선택되어 있으므로 쿼리의 형식은 IEnumerable<Student>입니다. var 키워드를 사용하여 코드에서 암시적 형식 지정을 사용할 수도 있지만 결과를 더 분명하게 나타내기 위해 명시적 형식 지정이 사용됩니다. var에 대한 자세한 내용은 암시적으로 형식화된 지역 변수(C# 프로그래밍 가이드)을 참조하십시오.

    또한 쿼리의 범위 변수인 student가 소스의 각 Student에 대한 참조로 사용되어 각 개체에 대한 멤버 액세스를 제공한다는 것에 주의합니다.

// Create the query. 
// The first line could also be written as "var studentQuery ="
IEnumerable<Student> studentQuery =
    from student in students
    where student.Scores[0] > 90
    select student;

쿼리 실행

쿼리를 실행하려면

  1. 이제 쿼리를 실행하게 만드는 foreach 루프를 작성합니다. 코드에 대한 다음 사항에 주의합니다.

    • 반환된 시퀀스의 각 요소는 foreach 루프에서 반복 변수를 통해 액세스합니다.

    • 이 변수의 형식은 Student이고 쿼리 변수의 형식은 호환되는 IEnumerable<Student>입니다.

  2. 이 코드를 추가한 후 Ctrl + F5를 눌러 응용 프로그램을 빌드 및 실행하여 콘솔 창에서 결과를 봅니다.

// Execute the query. 
// var could be used here also. 
foreach (Student student in studentQuery)
{
    Console.WriteLine("{0}, {1}", student.Last, student.First);
}

// Output: 
// Omelchenko, Svetlana 
// Garcia, Cesar 
// Fakhouri, Fadi 
// Feng, Hanying 
// Garcia, Hugo 
// Adams, Terry 
// Zabokritski, Eugene 
// Tucker, Michael

다른 필터 조건을 추가하려면

  • 쿼리를 더 구체화하기 위해 where 절에서 여러 부울 조건을 결합할 수 있습니다. 다음 코드는 첫 번째 점수가 90점을 넘고 마지막 점수가 80점 미만인 학생을 쿼리에서 반환하도록 조건을 추가합니다. where 절은 다음 코드와 유사해야 합니다.

    where student.Scores[0] > 90 && student.Scores[3] < 80
    

    자세한 내용은 where 절(C# 참조)을 참조하십시오.

쿼리 수정

결과의 순서를 지정하려면

  1. 결과가 일정한 순서로 되어 있을 경우 결과를 더 쉽게 검색할 수 있습니다. 소스 요소의 액세스 가능한 임의 필드별로 반환된 시퀀스의 순서를 지정할 수 있습니다. 예를 들어 다음 orderby 절은 각 학생의 성에 따라 사전순으로 A부터 Z까지 결과의 순서를 지정합니다. 다음 orderby 절을 쿼리에서 where 문 바로 뒤 및 select 문 앞에 추가합니다.

    orderby student.Last ascending
    
  2. 이제 첫 번째 테스트의 점수에 따라 최고 점수부터 최하 점수까지 역순으로 결과의 순서를 지정하도록 orderby 절을 변경합니다.

    orderby student.Scores[0] descending
    
  3. 점수를 볼 수 있도록 WriteLine 형식 문자열을 변경합니다.

    Console.WriteLine("{0}, {1} {2}", student.Last, student.First, student.Scores[0]);
    

    자세한 내용은 orderby 절(C# 참조)을 참조하십시오.

결과를 그룹화하려면

  1. 그룹화는 쿼리 식의 강력한 기능입니다. group 절이 있는 쿼리는 그룹 시퀀스를 생성하고 각 그룹 자체는 Key와 해당 그룹의 모든 멤버로 구성된 시퀀스를 포함합니다. 다음 새 쿼리는 성의 첫 글자를 키로 사용하여 학생을 그룹화합니다.

    // studentQuery2 is an IEnumerable<IGrouping<char, Student>> 
    var studentQuery2 =
        from student in students
        group student by student.Last[0];
    
  2. 이제 쿼리 형식이 변경되었다는 것에 주의합니다. char 형식을 키로 포함하고 시퀀스와 Student 개체 시퀀스를 포함하는 그룹 시퀀스가 생성됩니다. 쿼리 형식이 변경되었으므로 다음 코드에서는 또한 foreach 실행 루프가 변경됩니다.

    // studentGroup is a IGrouping<char, Student> 
    foreach (var studentGroup in studentQuery2)
    {
        Console.WriteLine(studentGroup.Key);
        foreach (Student student in studentGroup)
        {
            Console.WriteLine("   {0}, {1}",
                      student.Last, student.First);
        }
    }
    
    // Output: 
    // O 
    //   Omelchenko, Svetlana 
    //   O'Donnell, Claire 
    // M 
    //   Mortensen, Sven 
    // G 
    //   Garcia, Cesar 
    //   Garcia, Debra 
    //   Garcia, Hugo 
    // F 
    //   Fakhouri, Fadi 
    //   Feng, Hanying 
    // T 
    //   Tucker, Lance 
    //   Tucker, Michael 
    // A 
    //   Adams, Terry 
    // Z 
    //   Zabokritski, Eugene
    
  3. Ctrl + F5를 눌러 응용 프로그램을 실행하고 콘솔 창에서 결과를 봅니다.

    자세한 내용은 group 절(C# 참조)을 참조하십시오.

변수의 형식이 암시적으로 지정되게 하려면

  • IGroupingsIEnumerables에 대한 코드를 명시적으로 작성하는 작업은 금방 지루해질 수 있습니다. var를 사용하면 동일한 쿼리와 foreach 루프를 훨씬 더 편리하게 작성할 수 있습니다. var 키워드는 개체의 형식을 변경하지 않으며 단순히 형식을 유추할 것을 컴파일러에 지시합니다. 형식을 변경 studentQuery 및 반복 변수 group 에 var 및 쿼리를 다시 실행 합니다. 이 경우 내부 foreach 루프에서 반복 변수의 형식은 여전히 Student로 지정되며 쿼리가 이전과 동일하게 작동합니다. s 반복 변수를 var로 변경하고 쿼리를 다시 실행하면 동일한 결과가 나타나는 것을 볼 수 있습니다.

    var studentQuery3 =
        from student in students
        group student by student.Last[0];
    
    foreach (var groupOfStudents in studentQuery3)
    {
        Console.WriteLine(groupOfStudents.Key);
        foreach (var student in groupOfStudents)
        {
            Console.WriteLine("   {0}, {1}",
                student.Last, student.First);
        }
    }
    
    // Output: 
    // O 
    //   Omelchenko, Svetlana 
    //   O'Donnell, Claire 
    // M 
    //   Mortensen, Sven 
    // G 
    //   Garcia, Cesar 
    //   Garcia, Debra 
    //   Garcia, Hugo 
    // F 
    //   Fakhouri, Fadi 
    //   Feng, Hanying 
    // T 
    //   Tucker, Lance 
    //   Tucker, Michael 
    // A 
    //   Adams, Terry 
    // Z 
    //   Zabokritski, Eugene
    

    var에 대한 자세한 내용은 암시적으로 형식화된 지역 변수(C# 프로그래밍 가이드)을 참조하십시오.

키 값별로 그룹의 순서를 지정하려면

  • 앞의 쿼리를 실행하면 그룹은 사전순으로 되어 있지 않습니다. 그룹에 이 순서를 지정하려면 group 절 뒤에 orderby 절을 제공해야 합니다. 그러나 orderby 절을 사용하려면 먼저 group 절에 의해 만들어진 그룹에 대한 참조로 사용되는 식별자가 필요합니다. 다음과 같이 into 키워드를 사용하여 이 식별자를 제공합니다.

    var studentQuery4 =
        from student in students
        group student by student.Last[0] into studentGroup
        orderby studentGroup.Key
        select studentGroup;
    
    foreach (var groupOfStudents in studentQuery4)
    {
        Console.WriteLine(groupOfStudents.Key);
        foreach (var student in groupOfStudents)
        {
            Console.WriteLine("   {0}, {1}",
                student.Last, student.First);
        }
    }
    
    // Output: 
    //A 
    //   Adams, Terry 
    //F 
    //   Fakhouri, Fadi 
    //   Feng, Hanying 
    //G 
    //   Garcia, Cesar 
    //   Garcia, Debra 
    //   Garcia, Hugo 
    //M 
    //   Mortensen, Sven 
    //O 
    //   Omelchenko, Svetlana 
    //   O'Donnell, Claire 
    //T 
    //   Tucker, Lance 
    //   Tucker, Michael 
    //Z 
    //   Zabokritski, Eugene
    

    이 쿼리를 실행하면 그룹은 이제 사전순으로 정렬됩니다.

let을 사용하여 식별자를 제공하려면

  • let 키워드를 사용하여 쿼리 식의 임의 식 결과에 대한 식별자를 제공할 수 있습니다. 이 식별자는 다음 예제와 같이 편의상 제공될 수도 있고 여러 번 계산할 필요가 없도록 식 결과를 저장하여 성능을 향상시킬 수도 있습니다.

    // studentQuery5 is an IEnumerable<string> 
    // This query returns those students whose 
    // first test score was higher than their 
    // average score. 
    var studentQuery5 =
        from student in students
        let totalScore = student.Scores[0] + student.Scores[1] +
            student.Scores[2] + student.Scores[3]
        where totalScore / 4 < student.Scores[0]
        select student.Last + " " + student.First;
    
    foreach (string s in studentQuery5)
    {
        Console.WriteLine(s);
    }
    
    // Output: 
    // Omelchenko Svetlana 
    // O'Donnell Claire 
    // Mortensen Sven 
    // Garcia Cesar 
    // Fakhouri Fadi 
    // Feng Hanying 
    // Garcia Hugo 
    // Adams Terry 
    // Zabokritski Eugene 
    // Tucker Michael
    

    자세한 내용은 let 절(C# 참조)을 참조하십시오.

쿼리 식에서 메서드 구문을 사용하려면

  • LINQ의 쿼리 구문 및 메서드 구문(C#)에 설명된 것처럼 일부 쿼리 작업은 메서드 구문에 의해서만 표현될 수 있습니다. 다음 코드는 소스 시퀀스에서 각 Student의 총 점수를 계산한 다음 해당 쿼리의 결과에서 Average() 메서드를 호출하여 클래스의 평균 점수를 계산합니다. 쿼리 식을 묶은 괄호에 주의합니다.

    var studentQuery6 =
        from student in students
        let totalScore = student.Scores[0] + student.Scores[1] +
            student.Scores[2] + student.Scores[3]
        select totalScore;
    
    double averageScore = studentQuery6.Average();
    Console.WriteLine("Class average score = {0}", averageScore);
    
    // Output: 
    // Class average score = 334.166666666667
    

Select 절에서 변환 또는 프로젝션하려면

  1. 쿼리에서는 소스 시퀀스의 요소와 다른 요소를 가진 시퀀스를 생성하는 것이 매우 일반적입니다. 이전 쿼리 또는 실행 루프를 삭제하거나 주석으로 처리하고 다음 코드로 바꿉니다. 쿼리는 Students가 아니라 문자열 시퀀스를 반환하며 foreach 루프에서 이 사실이 반영됩니다.

    IEnumerable<string> studentQuery7 =
        from student in students
        where student.Last == "Garcia" 
        select student.First;
    
    Console.WriteLine("The Garcias in the class are:");
    foreach (string s in studentQuery7)
    {
        Console.WriteLine(s);
    }
    
    // Output: 
    // The Garcias in the class are: 
    // Cesar 
    // Debra 
    // Hugo
    
  2. 이 연습의 앞부분에 있는 코드는 평균 클래스 점수가 약 334라는 것을 나타냈습니다. 클래스 평균보다 총 점수가 높은 Students의 시퀀스를 생성하려면 해당 Student ID와 함께 익명 형식을 select 문에서 사용할 수 있습니다.

    var studentQuery8 =
        from student in students
        let x = student.Scores[0] + student.Scores[1] +
            student.Scores[2] + student.Scores[3]
        where x > averageScore
        select new { id = student.ID, score = x };
    
    foreach (var item in studentQuery8)
    {
        Console.WriteLine("Student ID: {0}, Score: {1}", item.id, item.score);
    }
    
    // Output: 
    // Student ID: 113, Score: 338 
    // Student ID: 114, Score: 353 
    // Student ID: 116, Score: 369 
    // Student ID: 117, Score: 352 
    // Student ID: 118, Score: 343 
    // Student ID: 120, Score: 341 
    // Student ID: 122, Score: 368
    

다음 단계

C#에서 쿼리를 사용하는 기본적인 측면에 익숙해진 후에는 원하는 특정 LINQ 공급자 형식에 대한 설명서와 샘플을 읽을 수 있습니다.

LINQ to SQL [LINQ to SQL]

LINQ to DataSet

LINQ to XML

LINQ to Objects

참고 항목

작업

연습: Visual Basic에서 쿼리 작성

개념

LINQ 쿼리 식(C# 프로그래밍 가이드)

추가 LINQ 리소스

기타 리소스

LINQ(통합 언어 쿼리)

C#에서 LINQ 시작