관리 메뉴

새로운 시작, GuyV's lIfe sTyle.

닷넷 게시판 만들기 Part 46 - 페이징을 위한 DB 쿼리문 구현 본문

ⓟrogramming/asp.net 게시판

닷넷 게시판 만들기 Part 46 - 페이징을 위한 DB 쿼리문 구현

가이브 2011. 6. 15. 15:59

 

2011/05/13 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 31
2011/05/16 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 32
2011/05/18 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 33
2011/05/19 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 34
2011/05/23 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 35
2011/05/25 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 36
2011/05/26 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 37
2011/05/27 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 38
2011/05/30 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 39
2011/05/31 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 40
2011/06/01 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 41
2011/06/08 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 42
2011/06/09 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 43
2011/06/13 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 44
2011/06/14 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 45


1. 닷넷 개발환경 준비, 테스트
2. 닷넷 알아보기 [7/7]
3. asp.net 컨트롤 [10/10]
4. 데이터베이스(DB) [7/7]
5. 닷넷 게시판을 만들어보기 전에.. [4/4]
6. 게시판 만들기 [16/..]



이전시간에 페이징을 구현할 수 있는 쿼리문을 직접 실행해보았다.
이 쿼리문의 결과 갯수는 무조건 페이지 당 글 수(우리는 10개) 이하로 고정되어 있다. 만약 12개의 자료가 게시판에 있고, 10개씩이니 리스트에서 1페이지는 10개, 2페이지는 2개가 나올 것이다.

먼저 미리 정해야 될 값들이 있다.


1. 페이지번호는 페이지간에 던져줄 때는 'page'라고 하고, 프로그램 변수에서는 int 형으로 NOW_PAGE 라고 지정하자.
2. 페이지당 글 수는 int 형으로 PAGE_SIZE 변수명으로 고정시키자.



이제부터 게시판에는 page 라는 값이 GET으로 계속 전달되어야 한다. (검색기능이 값을 넘겨주는 것처럼)

현재의 리스트를 출력하는 라이브러리를 구성해보자.
구성하기 전에 생각할 점은 페이지 기능인 리스트 하단에 숫자로 표현하는 페이지 이동과 리스트에서 해당 페이지 구간의 자료를 가져오는 것은 별개라고 생각하자.
연관이 있어보이나 사실 연관이 없다고 할 수 있다. 그래야 여러분들이 이해하기가 쉽다. ^^ 왜 그런지는 각자가 고민해보자.

board_list.aspx 리스트 페이지에서는 현재의 페이지 번호만 받아서 가지고 있으면 된다. 다른 변수들은 게시판 라이브러리인 Board.cs 에 정의해두고 땡겨쓰는 곳에서도 사용할 수 있게 하자.

먼저 Board.cs 의 클래스 변수로 PAGE_SIZE 변수를 정의한다.




접근한정자(제한자)를 public 으로 선언하게 되면 외부에서 읽을 수 있으며, 변경도 가능하다. 차후에 게시판마다 PAGE_SIZE 를 10이 아닌 다른 값으로 할 수 있겠다. 기본값이 10으로 보면 된다.

이제 저번에 해본 상수값 쿼리를 페이지 번호에 맞게 맞추기 위한 준비를 해보자.


SELECT * FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY board_id DESC) AS row_num, * FROM board tmp
)
AS BOARD_NUMBERED
WHERE
row_num > [A] AND row_num < [B]



일단 페이징을 위해서 우리가 구해야 하는 값은 A와 B이다. 조건이 'A 번째 초과를 하고  B 미만인 것'을 가져오는 것이다. 이는 이미 간단한 산수로 구해보았다. 페이지번호 now_page 를 기준으로 해보자.
[A]는 start_id, [B]는 end_id 변수로 표현해본다.





now_page 변수명으로 현재의 페이지 번호를 받는다. 위의 그림처럼 요청한 리스트가 만약 3 페이지일 경우, 21번부터 30번까지만 가져올 것이다.




위의 그림처럼 앞서 만든 쿼리문을 그대로 문자열로 만들었다. System.Text.StringBuilder 는 클래스 이름에서처럼 문자열을 만들어주는 객체인데, 보기 편하게 사용하였으니 별 신경쓰지 마시기 바란다. (하나의 쿼리 문자열을 만드는건 동일하다) 어쨌든 상수로 만들었던 기존 쿼리문에다가 페이지 번호에 따라 바뀌는 start_id, end_id 를 적용하는 것이다.

board_list.aspx 에서 이 메서드를 형식에 맞춰서 호출해보자. 첫 번째 인수 페이지번호는 임의대로 넣어준다. 검색어에 해당하는 두 개의 문자열은 그냥 비우자. 쿼리문이 제대로 잘 만들어지는 것을 확인하면 되겠다. 실제 적용하기 전에는 이렇게 한번 찍어서 눈으로 확인하는 과정을 거치는 것이 좋다.

Board BOARD_LIB = new Board();
BOARD_LIB.List(31, "", "");

이렇게 호출하면 다음처럼 최상단에 문자열이 출력될 것이다.




결과를 보니 31페이지에 해당하는 목록을 잘 가져올 것 같다.
다시 List(..) 메서드로 돌아가서 정리를 하자. 검색처리도 적용해야 하므로 검색어가 입력되었을 때에는 (search_target, search_word 가 빈 값이 아닐 때) 검색을 수행하자. 어려운게 있는가? 쿼리문을 잘 요리해주면 된다.
마무리를 해보자.





지금 우리가 작성중인 List(카테고리, 페이지명, 검색대상, 검색어) 메서드의 리턴을 void 에서 DataTable 로 변경해준다. 그리고 검색어까지 적용하기 위해 71,72 번째 줄처럼 검색어가 있다면 query 문자열에 WHERE 절을 추가해준다. 그리고 기존이 List(..) 와 마찬가지로 자료를 리턴해준다.

board_list.aspx 에서 호출하는 List(..) 메서드를 지금 만든 녀석으로 바꿔보자. 앞서 말했듯이 페이지 변수(int NOW_PAGE)를 클래스 변수로에 지정하자. 기본값을 1(페이지)로 주어 GET으로 넘어오는 page 값이 없다면 그대로 사용하기로 한다.



기존에는 검색하지 않을 때와 검색할 때를 오버로드된 메서드를 각각 호출한다. 이제는 같이 사용할 것이다. (같이 페이징을 적용해야 하기 때문이다) 단, 검색어가 없을 때는 해당 인수를 공백("") 으로 던져주자.





GET으로 page 값이 넘어왔다면 이것을 NOW_PAGE에 넣어준다. 그냥 열렸다면 아마 1이 들어갈 것이다.
기존 코드는 유지하고, 47번째 줄 처럼 검색일 때 관련 변수 두 개를 던져주고, 57번째 줄처럼 검색이 아니면 그냥 공백으로 넘겨준다. 이제 첫 실행시에 DataTable 인 dtList 는 1페이지의 글이 넘어올 것이다.


현재 보여지는 순번은 무조건 10부터 1까지 나올 것이다. 왜냐면 List(..) 의 결과로 넘어오는 DataTable 은 무조건 10개이하이기 때문이다. 페이지 테스트를 위해 주소창에 페이지 번호를 의미하는 page 의 값을 붙여서 열어보자. 글 목록이 바뀌면서 해당 페이지 번호에 맞게 열릴 것이다. 검색 기능도 잘 작동할 것이다.

지금까지 우리가 한 작업은 페이징 기능에 맞는 쿼리를 만들었다. 그리고 현재 열리고 있는 board_list.aspx 의 페이지 번호에 맞게 해당 자료를 쏙쏙 골라서 뽑아온 후 리턴시킨다. 이 리턴되는 자료는 언제나 지정한 페이지 사이즈 갯수(10개) 이하이기 때문에 예전에 Repeater 이벤트에서 가상의 번호를 지정한 녀석은 무조건 10개부터 번호가 감소하게 된다.

리스트 상황을 눈으로 확인을 쉽게 하기위해 디자인을 좀 더 꾸며보도록 하자.
총 페이지, 현재 페이지를 표시하는 것과 전체 글 수도 가져와보자. 일단 디자인이기 때문에 컨트롤만 배치하자. 전체 글 수 / 총 페이지 / 현재 페이지를 표시하는 컨트롤은 Label 으로 하고, id는 lblPage 라고 준다.


 


TOTAL_COUNT 와 NOW_PAGE 는 기존에 정의되어 있다. TOTAL_COUNT 는 이번 페이징 기능이 변경되면서 무조건 결과가 10이하로 넘어오기 때문에 이것을 따로 구해야한다. 쿼리선에서 결과의 갯수만 구하는 함수가 존재한다.

SELECT COUNT(*) FROM board


이 쿼리문은 board 테이의 레코드수를 int 형으로 리턴한다. Board.cs 라이브러리에 ListCount(..) 라는 메서드를 만들어서 TOTAL_COUNT 로 받도록 하자. 주의해야할 점은, 실제 리스트처럼 검색할 때와 그렇지 않을 때를 구분해서 쿼리를 만들어줘야한다.


이처럼 검색어가 있다면 카테고리 뒤에 AND 로 검색까지 적용하면 되겠다. 결과는 컬럼1개에, int 형이므로 Database.ExecuteQueryResult(..) 에서 리턴하는 object 형을 (int) 로 변환한 후 board_list.aspx 로 리턴한다.

이것을 board_list.aspx 에서 호출하고 TOTAL_COUNT 변수에 담아주자.



board_list.aspx 에서 리스트를 가져오는 부분이 조금 간소화 되었다. STYPE, SVALUE 변수에 값이 없다면 결국 빈 값이므로 호출하는 방법은 똑같으므로 if() { .. } else() { .. } 밖으로 빠진 것을 볼 수 있다.

지금까지 전체 글 수를 구했고, 현재의 페이지는 NOW_PAGE 에서 가지고 있으니 마지막으로 "총 페이지 수"를 구해보자.
총 페이지수를 알아내려면 현재 리스트의 전체 글 수(TOTAL_COUNT 변수에 담아둔 값)에서 페이지의 갯수를 나눠버리면 된다. 여기서 추가하여 혹시 나눈 나머지의 값이 있다면 한페이지가 더 필요하니 총 페이지에 +1을 해준다. 그러니까 총 30개 글이면 3페이지인데, 31개면 4페이지가 되어야 할 것이다.

페이지당 글 수는 Board.PAGE_SIZE 에 있고, 전체 글 수는 TOTAL_COUNT에 구해놨으니 클래스에 PAGE_COUNT 변수(int)를 하나 선언하고 여기에 담도록 하자.



실행 결과는 다음과 같다.




지금은 리스트 맨 하단에 1,2,3,4,5... 같은 페이지 이동이 없기 때문에 수동으로 주소에 &page=14 를 붙여서 페이지를 테스트해봐야 한다. 앞서 말했듯이, 페이지를 뽑아서 출력하는 것과 하단에 숫자로 페이지 이동하는 기능은 다르다고 생각하자.

뭐든 복잡하게 보이지만, 기능을 구현하기 위해서는 생각해보고 정리해본 것을 하나하나 퍼즐 맞추듯 끼워맞춰주면 된다.
그러니 처음이 문제다. 어떻게 만들까, 어떻게 구현할까? 이미 구현해본 사람이 있으니 그 사람들이 "이렇게 하면 된다~"하면 어떻게 왜 되는지를 열심히 파보자. 그리고 자기것으로 만들고, 더 좋은 방법을 위해서 고민해보고 또 만들어보자.

머릿속에 늘 그림을 그리면서 개발하시기 바란다. 하나하나 흐트려놓고 조립하는 과정을 스스로 해야한다.

그리고 꼭 결과물을 맞춰 만들 필요는 없다. 간단하게 하나하나 테스트로 "상수 값"을 집어넣고 결과를 확인해보자. 그러면 예상대로 잘 작동하는지, 그렇지 않은지를 알 수 있다. 중간중간에 끊어주는 연습도 하자. 그래야 어디서 문제가 발생했는지를 쉽게 파악할 수 있다.

이제 하단에 페이지를 이동하는 링크를 고민해보자. [이전페이지, 다음페이지] 기능부터 한 후에 해보는 것도 좋을 것이다.


다음시간에..

반응형
Comments