대부분의 웹 프로그래밍은 데이터베이스를 다루게 된다. 데이터베이스를 잘 설계해야 장차 프로그램의 기능을 향상하거나 유지관리 하는 일이 손 쉬워지게 된다. 이번 글에서는 간략히 데이터베이스를 설계하고 데이터를 추가하는 간단한 폼을 만들어 보자.
데이터베이스는 여러 가지 형태가 있으나 일반적으로 SQL을 쓰게 된다. 이곳에서 설명하는 예는 MS-SQL 2000을 기준으로 한다. 데이터베이스를 만들거나 테이블을 생성하는 방법은 여러 가지가 있으므로 자세한 내용은 생략하고 SQL 스크립트와 도표를 살펴 보도록 하자.
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[DNBBSPost]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[DNBBSPost]
GO
CREATE TABLE [dbo].[DNBBSPost] (
[PostSystemID] [int] IDENTITY (1, 1) NOT NULL ,
[BBSID] [int] NOT NULL ,
[PostNo] [int] NOT NULL ,
[Subject] [nvarchar] (300) COLLATE Korean_Wansung_CI_AS NOT NULL ,
[BodyText] [ntext] COLLATE Korean_Wansung_CI_AS NULL ,
[CreatorID] [int] NOT NULL ,
[CreatorName] [nvarchar] (50) COLLATE Korean_Wansung_CI_AS NOT NULL ,
[CreateDate] [datetime] NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[DNBBSPost] WITH NOCHECK ADD
CONSTRAINT [PK_DNBBSPost] PRIMARY KEY CLUSTERED
(
[PostSystemID]
) ON [PRIMARY]
GO

테이블은 DNBBSPost라는 이름으로 만들었고 이 테이블은 DNBBS라는 데이터베이스에 생성하였다. 보는 바와 같이 간략한 게시판 정보를 담을 수 있는 열을 구성하였다. PostSystemID는 기본키이자 ID이다. BBSID는 장차 여러 게시판을 지원하여야 하기 때문에 각 게시판을 나타내는 ID로 사용할 열이다. PostNo는 게시판의 게시물 앞에 붙는 번호를 말한다. 게시판 글을 지칭할 때 번호로 이야기하는 경우가 많으므로 지원하는 것이 좋다. Subject는 게시물의 제목, BodyText는 게시글의 내용 CreatorID는 게시자의 사용자ID이고 CreatorName는 사용자의 이름이다. 여기서 CreatorID는 integer로 된 데이터베이스의 키이다. 즉 현재의 게시판은 회원 데이터베이스가 있다는 것을 가정으로 하고 있다. CreateDate는 글을 작성한 시간을 말한다.
데이터베이스를 만들었으면 게시판프로젝트로 돌아가자. 웹 어플리케이션에서 데이터베이스에 대한 접근은 하나의 클래스로 몰아서 하는 것을 일반적으로 권장한다. 이것을 데이터베이스 추상화라고 하기도 하고 2티어, 3티어등의 어려운 말들도 많이 하는데 데이터베이스는 장차 다른 데이터베이스에 이식을 해야 할 필요도 있고 그 속의 구조도 변경될 수 있으며 따로 성능향상을 위한 튜닝도 해야 하므로 한 곳으로 몰아 두는 것이 여러모로 유리하다.
데이터베이스에 접근하는 클래스를 DataController.cs라는 파일에 아래와 같이 생성한다.
using
System;
using
System.Collections;
using
System.Data;
using
System.Data.SqlClient;
namespace
DotNetBBS
{
///
///
DataController
에 대한 요약 설명입니다.
///
public
class PostController
{
string myConnString = "Server=localhost;Database=DotNetBBS;uid=xxxx;pwd=xxxxxx;";
public PostController()
{
}
public
int Add(PostInfo pi)
{
SqlConnection myConnection = new SqlConnection(myConnString);
myConnection.Open();
string myQuery = string.Format(
"insert DNBBSPost (BBSID, PostNo, Subject, BodyText, CreatorID, CreatorName, CreateDate) " +
"values ({0},{1},'{2}','{3}',{4},'{5}',getdate())", pi.BBSID, pi.PostNo, pi.Subject, pi.BodyText, pi.CreatorID, pi.CreatorName);
SqlCommand myCommand = new SqlCommand(myQuery, myConnection);
int r = myCommand.ExecuteNonQuery();
myConnection.Close();
return r;
}
public
void Update(PostInfo pi)
{
SqlConnection myConnection = new SqlConnection(myConnString);
myConnection.Open();
string myQuery = string.Format(
"update DNBBSPost set " +
"Subject='{0}' " +
"where PostSystemID={1}", pi.Subject, pi.PostSystemID);
SqlCommand myCommand = new SqlCommand(myQuery, myConnection);
myCommand.ExecuteNonQuery();
myConnection.Close();
}
public
void Delete(Int32 postSystemID)
{
SqlConnection myConnection = new SqlConnection(myConnString);
myConnection.Open();
string myQuery = string.Format("delete from DNBBSPost where PostSystemID={0}", postSystemID);
SqlCommand myCommand = new SqlCommand(myQuery, myConnection);
myCommand.ExecuteNonQuery();
myConnection.Close();
}
}
}
현재는 Add, Update, Delete의 세가지 메서드만 구현하고 있다. myConnString이라 이름 붙여진 데이터베이스 접속 문자열은 장차 Web.config으로 이동시켜야 할 내용이다. 보안상의 이유와 관리의 편리함을 위해서 프로그램 안에 두는 것 보다는 Web.confing에 두는 것이 유리하기 때문이다. 좋은 성능과 제대로 된 데이터베이스 추상화를 위해서는 모든 SQL쿼리를 저장프로시저로 만드는 것이 원칙이나 개발단계에서는 스크립트를 자주 수정하는 일이 다소 번거로운 부분이 있으므로 일단 이런 형식으로 만들었다가 최종적으로 저장프로시저로 옮기는 방법도 나쁘지 않다.
소스를 잘 보면 PostInfo라는 클래스를 사용하고 있는데 데이터베이스에 있는 구조체를 프로그램에서 쓰기 편하도록 따로 구현된 클래스이다. 소스는 아래와 같다.
using
System;
namespace
DotNetBBS
{
///
///
DataInfo
에 대한 요약 설명입니다.
///
public
class PostInfo
{
Int32 mPostSystemID;
Int32 mBBSID;
Int32 mPostNo;
string mSubject;
string mBodyText;
Int32 mCreatorID;
string mCreatorName;
DateTime mCreateDate;
public PostInfo()
{
}
public Int32 PostSystemID
{
get { return mPostSystemID; }
set { mPostSystemID = value; }
}
public Int32 BBSID
{
get { return mBBSID; }
set { mBBSID = value; }
}
public Int32 PostNo
{
get { return mPostNo; }
set { mPostNo = value; }
}
public
string Subject
{
get { return mSubject; }
set { mSubject = value; }
}
public
string BodyText
{
get { return mBodyText; }
set { mBodyText = value; }
}
public Int32 CreatorID
{
get { return mCreatorID; }
set { mCreatorID = value; }
}
public
string CreatorName
{
get { return mCreatorName; }
set { mCreatorName = value; }
}
public DateTime CreateDate
{
get { return mCreateDate; }
set { mCreateDate = value; }
}
}
}
별다른 내용은 없고 데이터베이스의 각 열을 속성으로 정의해 두었다. 이것도 장차 데이터베이스 추상화와 관리의 편리함을 위해서 이런 식으로 하는 것이 좋다. 멤버를 직접 사용하지 않고 속성으로 사용하는 이유는 차후에 멤버의 형식이 바뀌더라도 상위에서 속성을 사용하는 프로그램을 수정하지 않기 위해서이다. 이 파일은 DataInfo.cs라는 파일로 저장한다.
자 이제 데이터베이스 테스트를 겸해서 간단한 게시물을 올리는 페이지를 만들어 보자. 아래와 같이 AddNewPost.ascx를 생성한다. 이 컨트롤은 장차 게시물을 올리는 내용을 담게 될 사용자 정의 컨트롤이다. 이 컨트롤에서는 한글을 사용하고 있는데 앞으로 한글 관련한 모든 인코딩은 UTF-8을 사용한다. 현재 웹 프로그래밍에서는 일반적으로 euc-kr을 많이 사용하지만 앞으로의 대세는 모든 언어를 동시에 표현가능 한 UTF-8을 사용하는 것이 일반적이 될 것이다. 이 ascx파일도 한글을 사용하고 있으므로 “파일>저장고급옵션”에서 UTF-8을 저장 형식으로 설정해서 저장하도록 한다.
<%@ Control Language="c#" AutoEventWireup="false" Codebehind="AddNewPost.ascx.cs" Inherits="otNetBBS.AddNewPost" TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
°
<
table
>
<
tr
>
<
td
>
제목:
</
td
>
<
td
>
<
asp:TextBox
Runat
="server"
ID
="txtSubject"></
asp:TextBox
>
</
td
>
</
tr
>
<
tr
>
<
td
>
내용:
</
td
>
<
td
>
<
asp:TextBox
Runat
="server"
ID
="txtBodyText"
Width
="400px"
Rows
="20"
TextMode
="MultiLine"></
asp:TextBox
>
</
td
>
</
tr
>
<
tr
>
<
td
>
</
td
>
<
td
>
<
asp:LinkButton
Runat
="server"
ID
="lbtnAddNewPost">
글 올리기</asp:LinkButton>
</
td
>
</
tr
>
</
table
>
코드는 아래와 같다.
namespace
DotNetBBS
{
using System;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
///
///
AddNewPost
에 대한 요약 설명입니다.
///
public
class AddNewPost : System.Web.UI.UserControl
{
protected System.Web.UI.WebControls.TextBox txtSubject;
protected System.Web.UI.WebControls.TextBox txtBodyText;
protected System.Web.UI.WebControls.LinkButton lbtnAddNewPost
;
private
void Page_Load(object sender, System.EventArgs e)
{
}
#region
Web Form
디자이너에서 생성한 코드
override
protected
void OnInit(EventArgs e)
{
//
// CODEGEN:
이 호출은 ASP.NET Web Form 디자이너에 필요합니다.
//
InitializeComponent();
base.OnInit(e);
}
private
void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
lbtnAddNewPost.Click += new EventHandler(this.AddNewPost_Click);
}
#endregion
private
void AddNewPost_Click(object source, System.EventArgs e)
{
PostController pc = new PostController();
PostInfo pi = new PostInfo();
pi.Subject = txtSubject.Text;
pi.BodyText = txtBodyText.Text;
pi.CreatorID = 1;
pi.CreatorName = "Tester";
pi.PostNo = 1;
pi.BBSID = 1;
pc.Add(pi);
txtSubject.Text = "";
txtBodyText.Text = "";
}
}
}
볼드로 된 부분만 주의해서 살펴보면 이해에는 별 어려움이 없을 것으로 생각된다. 제목과 내용을 입력 받아서 데이터베이스에 저장하는 프로그램이다. 실행을 하기 전에 한글이 제대로 나오기 위해서는 Web.config을 수정할 필요가 있다. 기본으로 만들어지는 Web.config의 섹션은 아래와 같은데
< globalization
requestEncoding="utf-8"
responseEncoding="utf-8"
/>
다소 부족하므로 다음과 같이 수정한다.
< globalization
culture="ko-KR"
uiCulture="ko"
requestEncoding="UTF-8"
responseEncoding="UTF-8"
fileEncoding="UTF-8" />
이와 관련된 자세한 설명은 다소 복잡한 감이 있으므로 차후로 미루도록 한다. 이제 AddNewPost.ascx가 프로젝트에서 표시될 수 있도록 BBS.ascx에 아래와 같은 내용을 추가한다.
<%@ Register TagPrefix="Gosu" TagName="AddNewPost" Src="AddNewPost.ascx" %>
<Gosu:AddNewPost runat="server"></Gosu:AddNewPost>
모든 것이 완료 되었으면 실행을 한다. 아래 화면은 실제 실행화면이다.
내용을 입력하고 글 올리기를 한 후 데이터베이스에 잘 저장되고 있는지 확인한다.
프로젝트 소스파일 다운로드 링크:
http://www.code99.net/tabid/842/ItemID/10/Default.aspx