닷넷프로그래밍정복 김상형저 가메출판사

Languate INtegrated Query(.Net 3.5이상에서 지원)

쿼리란 데이터 소스에서 특정고전에 맞는 데이터를 검색하는 지시사항이다.

LINQ는 언어에 독립적인 쿼리문이다. 여기서 언어라는 용어는 이중의 의미를 가진다. 쿼리 대상인 데이터소스를 칭하기도 하고 쿼리 실행언어를 칭하기도 하는데 양쪽 다 독립적이다.

LINQ는 쿼리문에 객체지향 개념을 도입하였고 인텔리센스나 디버거의 도움도 쉽게 받을수 있다. 데이터변경은 불가능하고 정렬이나 그룹핑정도만 가능하다. 향후 발전 가능성은 높으나

아직은 베타수준이라 지원하는 언어도 C#3.0 / VB9.0뿐이고 결과도 COM처럼 될지 안될지는 두고 볼일이다.

ex1. SQL 문과 유사한 점이 많다

int[] ar = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            IEnumerable<int> Query = from n in ar where ( n % 3 == 0 ) select n;
            foreach(int k in Query)
                Console.WriteLine(k);

ex2

 var Files = from f in Directory.GetFiles("c:\\") select f;
            foreach (var f in Files)
                Console.WriteLine("이름 " + f);

데이터 소스의 최소요건인 열거가능만 갖추어지면 DB / XML / FILE정보 등 활용을 다양하게 적용할수 있다

 

쿼리 표현식

from - where        -  select

           orderby        group

           let

의 형식을 가지고 있고 from으로 시작해서 select 식으로 끝난다.

형식은 순회변수 in 데이터 소스

순회변수의 타입은 비제네릭일때는 명시해야 하고 그렇지 않으면 굳이 명시하지 않아도 좋다

 

표준쿼리 처리자

쿼리표현식은 불행히도(!) 언어의 기능일뿐 닷넷 자체의 기능이 아니다. 그래서 모든 쿼리는 CLR이 이해할수 있는 메소드로 번역되어야만 실행할수 있다. 가급적 가독성을 높이기 위해서 쿼리문을 쓰는 것이 좋지만 아직까지 모든 쿼리문을 표현하지는 못한다. 그럴떄는 부득이하게 메소드를 바로 호출하게 된다.

  • Count  개수를 구한다
  • Sum 합계를 구한다
  • Average 평균을 구한다
  • Max 최대값을 구한다
  • Min 최소값을 구한다
  • OrderBy 요소등을 정렬한다
  • Select 결과셋의 프로젝션을 생성한다
  • Distnct 중복을 제거한다
  • Except 차집합을 구한다
  • Intersect 교집합을 구한다
  • Union 합집합을 구한다
  • All 모든 요소가 조건을 만족하는지 조사한다
  • Any 하나의 요소라도 조건을 만족하는지 조사한다
  • Contains 지정한 요소가 포함되어 있는지 조사한다
  • Take 지정한 위치에서 컬렉션을 분할한다
  • First 컬렉션의 첫번째 요소를 구한다
  • Last 컬렉션의 마지막 요소를 구한다
  • ElementAt 지정한 첨자의요소를 구한다

 

쿼리의 실행

쿼리를 생성하는 것과 실행하는 것은 별개이다. 쿼리를 생성하는 것은 단지 데이터를 읽을 준비만 하는 것이며 쿼리에 의해 생성된 결과셋을 순회하면서 읽어야 비로소 원하는 데이터를 얻을수 있다. 이것을 지연된 실행

(Deferred Execution)라고 한다.

ex.

int[] ar = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            IEnumerable<int> Query = from n in ar select n; // 쿼리 생성
            foreach (int k in Query) //데이타 셋 순회
                Console.WriteLine(k);

            Console.WriteLine();
            ar[2] = 9999;//데이타 셋에 반영 안됨
            foreach (int k in Query)//데이타 셋 순회
                Console.WriteLine(k);

쿼리를 실행할때마다 다른 결과가 리턴될수 있는데 이를 현재성이라고 한다. 순회시점의 정확한 값을 실시간으로 저사함으로써 현재성이 높다. 지연된 실행은 성능향상에 유리하다. 하지만 예외도 있다. 단일값을 반환하는 Count 류 함수는 굳이 지연시킬 필요가 없으니까 바로 반환한다.

 

 

고급쿼리

2.1 프로젝션 - 결과셋의 출력형태를 데이터 소스와는 다르게 변형하는 것

ex.

 People[] arPeople = { new People("한가인",18, true),
                                    new People("한예슬", 19, false),
                                    new People("남상미", 20, true),
                                    new People("강성연", 21,false) };


            IEnumerable<ResultNameAge> Query = from p in arPeople select new ResultNameAge(p.Name, p.Age);

            foreach (ResultNameAge k in Query)
                Console.WriteLine("이름 {0} 나이 {1}", k.Name, k.Age);

결과셋은 쿼리문에서 딱 한번 쓰고 말 것이니까 굳이 클래스로 선언하지 않고 원하는 멤버들로 구성된 객체를 생성할수 있다.

var Query = from p in arPeople select new { Name = p.Name, Age = p.Age };

이것을 익명타입으로 바꾼다면,

var Query = from p in arPeople select new { p.Name, p.Age };

익명타입이 다른 타입의 부분 집합일 경우 멤버의 이름을 생략하면 원본 타입의 이름을 그대로 따른다는 규칙이 있다.

 

그리고 프로젝션 기능으로  XML로 결과물을 만들어낼수 있다.

ex.

 var Query = new XElement("사람들", from p in arPeople
                                            select new XElement("사람",
                                                new XElement("이름", p.Name), new XElement("나이", p.Age),
                                                new XElement("남자", p.Male)));
Console.WriteLine(Query);

 

2.2 필터링 및 정렬

where 절 - 이 조건에 맞는 항목만 출력한다

orderby 절 - 결과셋의 출력순서를 지정한다. 디폴트는 오름차순이고 내림차순을 원할떄는 끝에 descending 붙여야 한다.

let 절 - 결과셋을 가공하여 임시변수에 저장하는 역할을 한다. 쿼리문 내에서 임시로 사용할 변수가 필요할때 let문으로 변수를 선언하고 이후 출력이나 조건, 점검 등에 이 변수를 활용할수 있다.

 

2.3 그룹핑

group by 절 - 특정 키를 기준으로 하여 요소들을 그룹별로 구분하여 출력하는 것이다. 그룹핑을 위해서는 내부적으로 키를 기준으로 정렬하고 같은 키를 가진 요소들을 소그룹으로 엮는 번잡한 처리를 해야 한다.

ex.

class Staff
{
    public Staff(string aName, string aDepart, int aSalary)
    {
        Name = aName;
        Depart = aDepart;
        Salay = aSalary;
    }
    public string Name;
    public string Depart;
    public int Salay;

}

 

 Staff[] arStaff = { new Staff("김유진", "초등부", 180),
                                  new Staff("김유경", "대학부", 195),
                                  new Staff("김상아", "초등부", 175),
                                  new Staff("김소연", "초등부", 170),
                                  new Staff("손화진", "중등부", 180),
                                  new Staff("곽민지", "중등부", 200),
                                  new Staff("허소림", "대학부", 210),
                                  new Staff("노찬영", "대학부", 187),
                                  new Staff("임유미", "고등부", 130),
                                
                              };

            IEnumerable<IGrouping<string, Staff>> Query = from p in arStaff group p by p.Depart;

            foreach(IGrouping<string, Staff>g in Query)
            {
                Console.WriteLine("\r\n" + g.Key);
                foreach(Staff k in g)
                    Console.WriteLine("이름 {0} 월급 {1}", k.Name, k.Salay);

            }

타입을 쓰면 복잡할수 있으니 암묵적 타입을 쓰면 var 훨씬 간단해진다.

ex

 var Query = from p in arStaff group p by p.Depart;

            foreach (var g in Query)
            {
                Console.WriteLine("\r\n" + g.Key);
                foreach (Staff k in g)
                    Console.WriteLine("이름 {0} 월급 {1}", k.Name, k.Salay);

            }

 

into 절 - let 절과 비슷한데 그룹핑 또는 조인한 쿼리에 임시적인 식별자를 부여하는 역할을 한다.

ex var Query = from p in arStaff group  p by p.Depart into gp orderby gp.Key. Select gp;

 

서브쿼리와 조인

서브쿼리는 쿼리문안에ㅔ 또 다른 쿼기가 있는 것이다. 연ㅅ곡되는 질문을 하나로 합칠수 있으며 SQL의 서브쿼리와 개념상 동일하다.

ex var Query = from p in arStaff where p.Salary == (from p2 in arStaff select p2.Salary).Max() select p.Name;

이 글은 스프링노트에서 작성되었습니다.

by 무위자연 2008. 8. 27. 15:03