Taeyo.NET - ASP.NET 2.0 강좌최초작성일 : 2007 년 12 월 17 일강좌최종수정일 : 2008 년 01 월 01 일 강좌읽음수 : 회 작성자 : kobukii( 김경균 ) 편집자 : Taeyo( 김태영 ) 강좌제목 : LINQ to SQL 강좌전태오의잡담 > 이번강좌는태오사이트의멤버이자, Microsoft MVP 인김경균님이제공하는 LINQ 에관한이야기입니다. 많은분들이관심을가지고있는 LINQ 에대해기본적인개념을이해할수있는강좌가될예정이니많은관심을부탁드립니다. LINQ to SQL 에대하여알아보자 이번강좌에서는 LINQ to SQL 을사용하는방법을간단한 Blog 예제를통해알아보도록하겠습니다. LINQ to SQL 은 LINQ 의한부분으로 SQL 서버의데이터를좀더편리하고직관적으로다룰수있게해주는 Microsoft 의새로운기술입니다. 최신버전의 LINQ 는.NET Framework3.5 가정식릴리즈되면서약간변경된부분이있으며본강좌에서는새롭게릴리즈된.NET Framework3.5 기반으로코드를작성하였습니다. 또한이글의모든코드는 Visual Studio 2008 RTM 버전으로작성되었습니다. 1. 웹프로젝트생성및 dbml(linq to SQL Classes) 생성 가장먼저 Web Project 를생성합니다. 웹어플리케이션을생성한후프로젝트및솔루션이름을 Lec_Blog 로입력합니다.
다음으로 LINQ to SQL C lasses 템플릿을선택하여 Blog.dbml 이라는이름으로파일을생성합니다. LINQ to SQL Classes 를생성하면 LINQ to SQL Designer 화면이나타나게되며이영역에데이터베이스를표현하는모델클래스를추가할수있습니다. 테이블, 저장프로시저, 사용자정의함수등이추가되면 LINQ to SQL Classes 는실제데이터베이스의각테이블을나타내는프로퍼티와저장프로시저를나타내는매서드등을포함하는 DataC ontext 클래스를생성하게됩니다. DataC ontext 클래스는변경된데이터를적용하거나데이터베이스로부터데이터를쿼리할때반드시사용하게되는 LINQ to SQL 의핵심이되는클래스입니다. LINQ to SQL Classes 파일을추가하면다음과같은 LINQ to SQL Designer 화면이나타나게됩니다.
LINQ to SQL Designer 의왼쪽영역에테이블을끌어놓게되면데이터클래스를자동으로생성합니다. 오른쪽영역은저장프로시저또는사용자정의함수를끌어놓을경우각저장프로시저와사용자정의함수에해당되는매서드를자동으로생성합니다. LINQ to SQL Designer 의왼쪽영역에테이블을추가해보도록하겠습니다. 우선 Server Explorer 을열고데이터베이스에연결합니다. 미리추가한 Lec_Blog 데이터베이스를선택하고 ok 버튼을클릭합니다. 데이터베이스가추가되면아래이미지와같은형태로 Server Explorer 가구성됩니다.
Server Explorer 에서 Category 테이블과 Post 테이블을 LINQ to SQL Designer 의왼쪽영역끌어놓으면끌어놓은각테이블들이시각적으로표시됩니다. 이제 LINQ to SQL 을이용하여간단한블로그개발을하기위한기본적인준비가완료되었습니다. 테이블스키마및소스코드는여기서다운로드받으실수있습니다. 다운로드받으시려면클릭하세요 2. 데이터가져오기 (SELECT) Post.aspx 라는웹페이지를추가합니다. 이페이지는포스트를작성, 수정그리고삭제하는기능을갖고있는페이지입니다. 페이지의구성은카테고리를선택할수있는 DropDownLIst, 제목과텍스트를입력받는 TextBox 그리고저장을위한 Button 으로구성되어있습니다. 첫번째로새포스트를작성할때카테고리를선택할수있는기능을추가하도록하겠습니다. BlogDataContext db; protected void Page_Load(object sender, EventArgs e) db = new BlogDataContext();
if (!IsPostBack) cateogrybind(); private void cateogrybind() IQueryable<Category> category = from c in db.categories select c; //IQueryable<Category> category = db.categories.select(p => p); ddlcategory.datasource = category; ddlcategory.databind(); 위의코드에서가장먼저알아야할부분이 BlogDataContext 입니다. 앞에서도말한것처럼 DataContext 클래스는변경된데이터를적용하거나데이터베이스로부터데이터를쿼리할때반드시사용하게되는 LINQ to SQL 의핵심이되는클래스입니다. 코드의 categorybind 매서드를보면쿼리구문을이용하여 C ategory 테이블의모든데이터를가져와 IQueryable<Category> 타입의변수에할당합니다. 쿼리구문을보면 from 절에서데이터를가져오게될데이터소스를지정합니다. BlogDataC ontext 의인스턴스인 db 개체를이용하여 C ategories 에접근하며이 C ategories(c ategory 테이블클래스 ) 의 entity 를 c 라가정하고특별한조건 (Where 절 ) 없이 c 를 Select 합니다. 이는카테고리테이블의모든데이터를가져온다는의미와같습니다. 쿼리구문아래주석으로처리된부분은쿼리구문을사용하는대신 Lambda Expression 을사용하여데이터를가져오는또다른방법입니다. 어떤방법을사용해도결과는동일합니다. 가져온데이터를 DropDownList 의 DataSource 에할당하고바인드를합니다. DropDownList 의 DataSource 로 ListItemC ollection 타입을사용하지않을경우에는 DataTextField 와 DataValueField 를반드시지정해야합니다. 이를각각 CategoryName 과 CategoryID 로지정해주면 Category 를선택할수있는 DropDownList 가만들어지게됩니다. 데이터의조회는마지막챕터에서더자세히알아보도록하겠습니다. 3. 데이터저장 (INSERT) 다음으로포스트의내용을저장하는방법에대해알아보겠습니다. protected void btnsubmit_click(object sender, EventArgs e) Post post = new Post(); post.title = txttitle.text; post.content = txtcontent.text; post.pubdate = DateTime.Now; post.categoryid = Convert.ToInt32(ddlCategory.SelectedItem.Value); db.posts.insertonsubmit(post); LINQ to SQL Classes 에 Category 와 Post 테이블을끌어놓았기때문에각테이블의 entity 에해당하는 Post 및 Category 클래스가생성됩니다. 가장먼저 Post 의인스턴스를만듭니다. LINQ 는테이블의필드명을쉽게확인할수있도록완벽한인텔리센스를제공합니다. 생성된 post 개체의각필드에값을할당합니다. 마지막으로테이블에해당하는 db.posts 의 InsertOnSubmit 을호출합니다. Posts 의 InsertOnSubmit 매서드는매개변수로 Posts 의 entity 인 Post 타입의개체를받습니다. 여기서기존에 LINQ 를사용해보신분들께서는 InsertOnSubmit 매서드가생소할수있습니다. 기존에는분명 Add 매서드를이용하여데이터를추가하고 OnSubmitC hange 매서드를호출하여데이터를전송했었지만정식버전의출시와함께약간의매서드가변경되었습니다. Beta1 and Beta2VS 2008 RTM Add() AddAll() InsertOnSubmit() InsertAllOnSubmit()
Remove() RemoveAll() DeleteOnSubmit() DeleteAllOnSubmit() 위의표는 Beta 에서 RTM 로버전업되면서변경된매서드들입니다. 참고하세요.. 4. 데이터의수정및삭제 데이터를수정하거나삭제하기위해서는가장먼저수정이나삭제를하기위한데이터를가져와 entity 개체를생성해야합니다. Post post; int postid = Convert.ToInt32(Request.QueryString["postid"]); if (postid > 0) post = db.posts.single(p => p.postid == postid); 데이터의삽입과마찬가지로 entity 개체의각속성에값을할당합니다. post.title = txttitle.text; post.content = txtcontent.text; post.pubdate = DateTime.Now; post.c ategoryid = C onvert.toint32(ddlc ategory.selecteditem.value); 값을모두할당한다음변경된값을처리하기위해 BlogDataContext 의 SubmitChanges 매서드를호출하여수정을완료합니다. db.submitc hanges(); 데이터삭제의경우는 entity 개체를생성한후 db 개체의 DeleteOnSubmit 매서드를호출하기만하면삭제처리가이루어집니다. 5. 쿼리구문의용법및컨트롤데이터바인딩 지금부터조금더다양한 LINQ 쿼리구문을이용하여데이터를가져오고또한가져온데이터를 ListView 컨트롤에바인딩하는방법을블로그의매인페이지를만들면서보다자세히설명하도록하겠습니다. 블로그의메인페이지는왼쪽카테고리영역과오른쪽포스트목록영역으로나누도록하겠습니다. 이두부분은.Net Frameowrk3.5 에서새롭게등장한 ListView 컨트롤을사용하고있습니다.
<asp:listview ID="categoryList" ItemPlaceholderID="categoryItems" runat="server"> <LayoutTemplate> <ul style="margin:0 0 0 0;padding:0 0 0 0"> <asp:placeholder ID="categoryItems" runat="server"></asp:placeholder> </ul> </LayoutTemplate> <ItemTemplate> <li><a href="default.aspx?categoryid=<%#eval("categoryid") %>"> <%#Eval("CategoryName") %></a></li> </ItemTemplate> </asp:listview> ListView 컨트롤의사용법은본강좌의주제에서벗어나기때문에간단하게설명하도록하겠습니다. ListView 컨트롤은간단히 LayoutTemplete 과 ItemTemplete 영역으로나눌수있는데 LayoutTemplete 은목록의헤더또는목록을감싸는 Tag 를지정하여기본 Layout 을지정하는영역입니다. 반복되는데이터를표현하는부분을 PlaceHolder 를통해지정해주고이컨트롤의아이디를 ListView 컨트롤의 ItemPlaceholderID 속성에지정합니다. ItemTemplete 영역은실제반복되는부분을만들어줍니다. 데이터는 Eval 매서드를통해지정해줍니다. 이곳에서반복적으로생성된코드가 LayoutTemplete 의 PlaceHolder 컨트롤에표현됩니다. 다음으로데이터를 ListView 컨트롤에바인딩하는코드는아래와같습니다. List<Category> categories = db.categories.tolist(); categorylist.datasource = categories; categorylist.databind(); 코드는 DropDownList 에데이터를바인딩했을때와상당히유사합니다. 다른점은 ToList() 확장매서드를사용하여반환타입을 List<T> 타입으로한다는것입니다. 쿼리구문은기본적으로 IQueryable<T> 형태로만들어지게됩니다. 이타입은루프를돌면서값을사용하기시작할때실제 DB 와통신을하여값을가져오게됩니다. 위의이미지에서도확인되듯이디버그를해보면 var categories 부분에서는아무런데이터를받아오지못하고 DataSource 에값을할당하였을때비로소데이터를받아온것을볼수있습니다.
위의코드는 ToList() 확장매서드를사용한경우인데이때는 categories 변수에마우스를올리자바로값을받아온것을확인할수있습니다. ToList(), ToArray() 와같은확장매서드를사용하면데이터의타입을변경하는동시에즉시데이터베이스와통신을하여값을받아올수있습니다. 마지막으로 Where 구문을사용하여조건별로데이터를가져오고 Skip 과 Take 확장매서드를사용하여페이징을처리하는부분에대해알아보도록하겠습니다. 1) 조건절을이용한데이터조회및정렬 ( 단일포스트가져오기 ) List posts = (from p in db.posts where p.postid == postid orderby p.pubdate descending // 정렬 select p).tolist(); 위의코드에서는 where 절을사용하여 PostID 값을비교하여데이터를가져오며 orderby 절을이용하여 PubDate 를기준으로내림차순으로정렬합니다. 2) 페이징 ( 한화면에보여줄포스트들을가져오기 ) List<Post> posts = (from p in db.posts orderby p.pubdate descending select p).skip(currentpageidx * itemc ount).take(itemc ount).tolist(); PubDate 를기준으로정렬하며 Skip 확장매서드를통해 [ 현재페이지번호 * 한페이지의항목수 ] 만큼을 skip 하고 Take 확장매서드를사용하여한페이지의항목수만큼가져옵니다. 3) 조건절과페이지을모두이용한데이터조회 ( 카테고리별목록을페이징을통하여가져오기 ) List<Post> posts = (from p in db.posts where p.categoryid == categoryid orderby p.pubdate descending select p).skip(currentpageidx * itemc ount).take(itemc ount).tolist(); 위에서가져온데이터를 ListView 컨트롤에바인딩하기위해 ListView 컨트롤을구성하면 // Category 영역 <asp:listview ID="ListView1" runat="server" ItemPlaceholderID="categoryItems"> <LayoutTemplate> <ul style="margin:0 0 0 0;padding:0 0 0 0"> <asp:placeholder ID="categoryItems" runat="server"></asp:placeholder> </ul> </LayoutTemplate> <ItemTemplate>
<li> <a href='default.aspx?categoryid=<%#eval("categoryid") %>'> <%#Eval("CategoryName") %></a> </li> </ItemTemplate> </asp:listview> // 포스트영역 <asp:listview ID="postList" ItemPlaceholderID="Items" runat="server"> <LayoutTemplate> <asp:placeholder ID="Items" runat="server"></asp:placeholder> </LayoutTemplate> <ItemTemplate> <div> <div id="titarea"> <span id="title" style="color:white;"> <a href="/default.aspx? postid=<%#eval("postid") %>"><%#Eval("title") %></a> </span> </div> <div id="descarea"> <span id="pubdate"><%#eval("pubdate") %></span> <span id="category"><%#eval("category.categoryname") %></span> <span id="edit"><a href="post.aspx?postid=<%#eval("postid") %>">[ 수정 ]</a> </span> </div> <div id="contentarea"> <%#Eval("content") %> </div> </div> </ItemTemplate> </asp:listview> 블로그포스트영역에서는 LayoutTemplate 에 PlaceHolder 컨트롤을추가하고 ItemTemplete 에제목영역과설명영역 ( 발행일, 카테고리, 수정버튼 ), 컨텐츠영역을각 div 태그로생성합니다. 데이터는 Eval 매서드를통하여지정을하는데여기서특이한점은 <%#Eval("C ategory.c ategoryname") %> 부분에서 C ategoryname 을가져오는것입니다. Post 테이블에는 C ategoryid 만존재할뿐 CategoryName 은존재하지않는데위의코드에서는 CategoryName 을지정해줬다는것입니다. 이는 Post 테이블이 CategoryID 속성을통해 Category 테이블과연관관계를맺고있으므로 Post 의 Category 개체를통해 CategoryName 에접근할수있게되는것입니다. 카테고리영역에서는 Unorder List(UL) 태그를 ListView 컨트롤에사용하여카테고리역영을생성합니다. LayoutTemplete 영역을 <ul> 태그로구성하고반복데이터가표현될영역을 PlaceHolder 컨트롤로지정합니다. ItemTelplete 영역은 <li> 태그를사용하여반복되는데이터를표현합니다. ListView 컨트롤은반드시테이블형태가아닌어떠한반복구조도표현할수있는장점이있습니다. 이번글에서는 LINQ to SQL 의간단한사용법에대해서알아보았습니다. ' 어떻게 LINQ to SQL 을사용할수있는가 ' 에초점을맞추었기때문에 LINQ 의일반적인사용법에대해서만알아보았습니다. 다음강좌는다양한쿼리구문과 Lambda Expression 예제를통해 LINQ 에대해보다자세히알아보도록하겠습니다. 그럼다음강좌에서다시뵙도록하겠습니다.^^ 감사합니다. 강좌목록으로..