C# 복습하기 14) LINQ

LINQ(Language INtegrated Query)

LINQ 쿼리 소개(C#)
docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/concepts/linq/introduction-to-linq-queries

 - 데이터 질의 기능

 - 발음은 '링큐'가 아니라 '링크'

 - 데이터를 골라 새 컬렉션으로 추출해야 하는 경우에 유용하게 사용된다.

 

From

 - 모든 LINQ 쿼리식은 반드시 from절로 시작한다.

 - from <범위 변수> in <데이터 원본>의 형식으로 사용한다.

 - 데이터 원본은 IEnumerable<T>를 상속하는 형식이 여야 한다. (배열, 컬렉션 등)

int[] numbers = {1, 2, 3, 4, 5};

var result = from n in numbers
             where n % 2 == 0
             orderby n
             select n;
             
foreach(int n int result)
    Console.WriteLine(n);

  (위의 식에서 각 절의 중간에 ,이나 ; 같이 구분짓는 부분이 없다는 것에 주의하자)

 

Where

 - 조건으로 필터링하는 역할을 한다.

var results = from    n in array
              where   n.num > 3
              select  n;

 

Orderby

 - 데이터 정렬한다. (기본 오름차순)

 - ascending 키워드를 쓰지않아도 기본은 오름차순으로 정렬되며, descending 키워드로 내림차순 정렬도 가능하다.

var results = from    n in array
              where   n.num > 3
              orderby n.num ascending
              select  n;

 

Select

 - 최종 결과를 뽑아내는 역할.

 - 무엇을 select하느냐에 따라 최종 IEnumerable <T>의 형식이 결정된다.

MyClass[] array;

var results = from    n in array
              where   n.num > 3
              select  n;
// 최종적으로 results 에는 IEnumerable<array> 가 들어간다.

 - 무명 형식을 이용하여 새로운 형식을 만들어 낼 수도있다.

 - LINQ와 무명형식을 함께 사용하면 가공된 데이터 컬렉션을 만들기 편하다.

[ 무명 형식 ]
 - 읽기 전용이라 한번 할당하고 나면 변경이 불가능하다.
 - 한번 사용하고 사용되지 않을 때 유용하게 사용된다.
MyClass[] array;

var results = from    n in array
              where   n.num > 3
              select  new { Name = n.Name, TwiceNum = n.num * 2 };

 

from 절 중첩

 - foreach와 유사하게 from 절을 중첩해서 사용하여 질의할 수도 있다.

var results = from n in array // 먼저 array 속에서 n을 찾고,
                  from s in n.Score // 그 n의 Score 프로퍼티들을 모아서 s로 질의한다.
                  where s < 50
              select new { c.name, Lowest = s };

 

group by로 데이터 분류

 - A는 from절에서 뽑아낸 범위 변수

 - B는 분류 기준

 - C는 그룹 변수

group A by B into C
var listProfile = from profile in arrProfile
                  orderby profile.Height
                  group profile by profile.Height < 175 into g
                  select new { GroupKey = g.Key, Profiles = g };
                  // Tuple을 쓴다면 select (GroupKey: g.Key, Profiles: g );

 - 최종적으로 var listProfile에는 조건의 true인 profiles의 배열과 false인 profiles의 두 개의 배열이 들어간다.

foreach(var Group in listProfile)
{
    Console.WriteLine($"175미만? : {Group.GroupKey}");
    
    foreach(var profile in Group.Profiles)
        Console.WriteLine($"{profile.Name}, {profile.Height}");
}

// 175미만 ?: true
//    이름, 158
//    이름, 123
// 175미만 ?: false
//    이름, 192
//    이름, 182

 

join으로 데이터 원본 연결

 - 특정 필드의 값을 비교하여 일치하는 데이터끼리 연결함.

 

내부 조인(Inner Join)

 - 두 데이터 원본에서 일치하는 데이터만 연결함. (교집합)

 - 기준 데이터 원본에는 존재하지만, 연결할 데이터 원본에는 존재하지 않는 경우 결과값에 포함되지않음.

 - on 절의 조건은 equal(동등)만 허용됨.

from a in A
join b in B on a.XXXX equals b.YYYY

[ Name, Height ]

A양 123
B군 168
C양 135

[ Name, Color ]

A양 초록
B군 보라
D군 주황

결과 : [ Name, Height, Color ]

A양 123 초록
B군 168 보라
var listProfile =
    from profile in arrProfile
    join product in arrProduct on profile.Name equals product.Color
    select new
    {
        Name = profile.Name,
        Height = profile.Height,
        Color = product.Color
    };

 

외부 조인(Outer Join)

 - 기준이 되는 데이터 원본이 모두 포함됨.

 - 기준에는 데이터가 있지만 합치는 데이터 원본에는 값이 없다면 해당 값이 비어있는 상태로 조인됨.

 

결과 : [ Name, Height, Color ]

A양 123 초록
B군 168 보라
C군 135  

 

var listProfile =
    from profile in arrProfile
    join product in arrProduct on profile.Name equals product.Work into ps
    from product in ps.DefaultIfEmpty(new Product(){Color = "없음"})
    select new
    {
        Name = profile.Name,
        Height = profile.Height,
        Color = product.Color
    };

 

LINQ 표준 연산자

MSDN : LINQ의 쿼리 구문 및 메서드 구문(C#)
https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/concepts/linq/query-syntax-and-method-syntax-in-linq

 - 지금까지의 코드는 LINQ 쿼리식이라고 부르는데,

   실제 .NET CTR에서는 이러한 쿼리들이 메서드 형태로 호출되어야한다.

 - 따라서 쿼리식 표현 외에도 메서드 식 표현을 알아두면 좋다.

// 쿼리식 표현
var v = from n in db.Orders                              
        where n.ID == "MyID"
        orderby n.Date ascending
        select n;

// 메서드식 표현
var v = db.Orders.Where(n => n.ID == "MyID")
                 .OrderBy(n => n.Date)
                 .Select(n => n);

 

 

댓글

Designed by JB FACTORY