기초 메모지

C# - LINQ(Language-Integrated Query) 본문

Languages/C#

C# - LINQ(Language-Integrated Query)

라큐브 2022. 1. 3. 13:58

LINQ(통합언어쿼리) 

.NET에서 데이터 쿼리를 실행하는 기술입니다.

LINQ 왜 사용할까?

- 데이터 처리에 용이합니다.

- 코드 길이가 줄어들어 관리와 가독성이 좋아집니다.

LINQ 사용 코드와 일반 코드 비교

- 짝수를 출력하는 로직을 서로 비교 해봅시다.

 

[일반 코드]

static void WithoutLinq()
{
    int[] ArrNumber = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    List<int> LisNumber = new List<int>();

    for (int i = 0; i < ArrNumber.Length; i++)
    {
        if (ArrNumber[i] % 2 == 0)
        {
            LisNumber.Add(ArrNumber[i]);
        }
    }

    foreach (var item in LisNumber)
    {
        Console.WriteLine(item);
    }
}

[LINQ 사용 코드]

static void WithLinq()
{
     int[] ArrNumber = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        // from 범위 변수 in 데이터
        // where 조건식
        // orderby 범위 변수 (오름차순 : 생략, 내림차순 : descending)
        // select 범위 변수(최종 결과)                                                                                                                                                          ㅣㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏ
        var Result = from Even in ArrNumber
                     where Even % 2 == 0
                     orderby Even
                     select Even;
}

 

코드를 비교해보면 일반 코드에 비해 LINQ 사용코드가 간결하고 가독성이 좋습니다.

 

LINQ 작성

from 범위변수 in 데이터 원본

where 조건식

orderby 범위 변수 (오름차순 : 생략, 내림차순 : descending)

select 범위 변수(익명 형식으로 최종 결과 출력)

 

예제 데이터

/// <summary>
    /// Q&A
    /// </summary>
    public class QNA
    {
        public int QnaNo { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }
        public string UserCd { get; set; }
        public string WriteDateTime { get; set; }
    }

    /// <summary>
    /// User
    /// </summary>
    public class User
    {
        public string UserCd { get; set; }
        public string UserNm { get; set; }
        public string CompanyNm { get; set; }
    }
    
static void WithLinq()
{
    List<QNA> QnaList = new List<QNA>()
    {
        new QNA {QnaNo = 0, Title = "제목 A", Content = "내용 A", UserCd = "A001", WriteDateTime = "2022-01-01"},
        new QNA {QnaNo = 1, Title = "제목 B", Content = "내용 B", UserCd = "A002", WriteDateTime = "2022-01-02"},
        new QNA {QnaNo = 2, Title = "제목 C", Content = "내용 C", UserCd = "A003", WriteDateTime = "2022-01-03"},
        new QNA {QnaNo = 3, Title = "제목 D", Content = "내용 D", UserCd = "A004", WriteDateTime = "2022-01-04"},
        new QNA {QnaNo = 4, Title = "제목 E", Content = "내용 E", UserCd = "A004", WriteDateTime = "2022-01-05"},
        new QNA {QnaNo = 5, Title = "제목 F", Content = "내용 F", UserCd = "A003", WriteDateTime = "2022-01-06"}
    };

    List<User> UserList = new List<User>()
    {
        //new User {UserCd = "A001", UserNm = "최윤미", CompanyNm = "구석기 전자"},
        //new User {UserCd = "A002", UserNm = "신현주", CompanyNm = "파산 은행"},
        new User {UserCd = "A003", UserNm = "윤진아", CompanyNm = "거북이 자동차"},
        new User {UserCd = "A004", UserNm = "박선아", CompanyNm = "사망 병원"},
        new User {UserCd = "A005", UserNm = "김서연", CompanyNm = "실패 컨설팅"}
    };
}

LINQ - Group By

LINQ Group By 형식은 다음과 같습니다.

 

from 범위변수 in 데이터 원본

group 범위변수 by 조건식

orderby 범위 변수 (오름차순 : 생략, 내림차순 : descending)

select 범위 변수(익명 형식으로 최종 결과 출력)

 

LINQ Group By 형식을 참고해 코드를 작성하면 다음과 같습니다.

var QueryQna = from Qna in QnaList
               group Qna by Qna.UserCd == "A004"
               into gQna
               orderby gQna.Key
               select gQna;

코드를 보시면 into 키워드가 추가되었는데 나중에 살펴보고 결과를 확인해봅시다.

group 키워드는 결과를 IGrouping<bool,T>  형식을 출력합니다. 

조건식으로 그룹화 되었으면 IGrouping<true,T> 아니라면 IGrouping<false,T> 를 출력합니다.

 

조사식을 확인해보면 UserCd가 A004가 아닌 그룹들은 IGrouping<false,T> 형식을 출력하고

UserCd가 A004인 그룹들은 IGrouping<true,T> 형식을 출력하고 있습니다. 

결과를 출력해보면 조건식으로 그룹화된 내용과 그렇지 않은 내용을 잘 출력되는 걸 볼 수 있습니다. 

 

foreach (var QnaGroup in QueryQna)
{
    Console.WriteLine(QnaGroup.Key? "A004" : "다른 코드");

    foreach (var Qna in QnaGroup)
    {
        Console.WriteLine("{0},{1},{2},{3},{4}",Qna.QnaNo, Qna.Title, Qna.Content, Qna.UserCd, Qna.WriteDateTime);
    }
}

LINQ - Into

into 키워드는 이전 쿼리 결과를 담고 있는 범위 변수 입니다. 

from Qna in QnaList
group Qna by Qna.UserCd == "A004"
// into 키워드 전 쿼리 실행 결과를 담고 있다.
// gQna 범위 변수는 Qna.UserCd를 "A004" 그룹화한 데이터를 담고있다.
into gQna

 

into 키워드는 Linq Group 연산에 한정되지 않고 다른 연산에서도 유용하게 이용할 수 있습니다.

 

 

LINQ - 내부 조인(INNER JOIN) / 조인 조건을 만족하는 행만 출력할 때 사용 됩니다.

LINQ Inner Join 형식은 다음과 같습니다.

 

범위 변수(원본) in 원본 데이터(Source)
join 범위 변수(비교) in 비교 대상 데이터(Target )
on 범위 변수(비교).필드 equals 범위 변수(원본).필드
select new { 무명 형식.필드 = 범위 변수(원본 Or 비교).필드};

 

LINQ Inner Join 형식을 참고해 코드를 작성하면 다음과 같습니다.

 

// 범위 변수 in 원본 데이터
// join 비교 대상 범위 변수 in 비교 대상 데이터
// on 비교 대상 범위 변수.필드 equals 데이터.필드
// select new { 무명 형식.필드 = 필요한 필드};
var QnaInnerJoin = from Qna in QnaList
    join User in UserList on Qna.UserCd equals User.UserCd
    select new {Title = Qna.Title, Content = Qna.Content, Writer = User.UserNm};

SQL과 같이 각각의 범위 변수의 기본키로 매칭하여 일치하는 값만 가져오는 코드 입니다.

Console.WriteLine("QnaInnerJoin");

foreach (var QnaJoin in QnaInnerJoin)
{
    Console.WriteLine("{0},{1},{2} ", QnaJoin.Title, QnaJoin.Content, QnaJoin.Writer);
}

 

LINQ - 왼쪽 외부 조인(LEFT OUTER  JOIN)

A, B를 조인했을때 A 전체 값과 B와 매칭되는 값을 조회합니다.

var QnaLeftOuterJoin = from Qna in QnaList
                       join User in UserList on Qna.UserCd equals User.UserCd 
                       into Nb
                       from User in Nb.DefaultIfEmpty(new User() { UserNm = "NULL"})
                       select new { Title = Qna.Title, Content = Qna.Content, Writer = User.UserNm };

코드를 살펴보면 DefaultIfEmpty  메서드를 확인할 수 있습니다.  이 메서드의 역할은 빈 값다른 값으로 바꿔 줍니다. 

LINQ와 SQL에서 조인 결과를 테이블로 확인해봅시다.

매칭되지 않은 값은 LINQ는 빈 값, SQL은 NULL 값으로 반환 합니다. 

 

그럼 그냥 빈칸으로 출력하면 되지 굳이 빈 값을 다른 값으로 바꾸는지 이해가 안될 수 있습니다.  

 

LINQ는 빈칸이 없는 행만 출력 합니다.

행에서 필드가 빈칸이 아닌 C,D,F,E 만 출력되니  외부 조인(Outer Join)이 아닌 내부 조인(Inner Join) 결과가 출력됩니다.

 

빈 칸을 없애야 외부 조인(Outer Join)을 이용할 수 있습니다.

from 범위변수(Target) in 범위 변수(into).DefaultIfEmpty(new Type() {  범위변수.필드(Empty) = "NULL"})

LINQ - 오른쪽 외부 조인(RIGHT OUTER  JOIN)

 A, B를 조인했을때 B 전체 값과 A와 매칭되는 값을 조회합니다.

- 원본 데이터와 비교 데이터의 위치만 바꾸면 됩니다.

var QnaRightOuterJoin = from User in UserList
                        join Qna in QnaList on User.UserCd equals Qna.UserCd
                        into Nb
                        from Qna in Nb.DefaultIfEmpty(new QNA() { Title = "NULL"})
                                    
                        select new { Title = Qna.Title, CompanyNm = User.CompanyNm, UserName = User.UserNm };

Console.WriteLine("QnaRightOuterJoin");

foreach (var UserJoin in QnaRightOuterJoin)
{
    Console.WriteLine("{0},{1},{2}", UserJoin.Title, UserJoin.CompanyNm, UserJoin.UserName);
}

 

반응형
Comments