0. 본 문서는…
0.1 본문서의 목적
- 본 문서는 ORM 툴의 일종인 SubSonic을 소개하고 간단한 활용법을 제시하여, 개발자들로 하여금
데이터베이스 액세스 코드를 작성하는 노력과 시간을 줄여주고, 본격적인ORM 툴들의(Nhibernate,
iBatis.Net 등) 사용에 친숙해질 수 있도록 안내하기 위함입니다.
0.2 작성정보
- 작성자 : OOO
- 작성일 : 2008년 7월14일
0.3 문서버전
- 0.9
0.4 목차
1. SubSonic 이란?
2. SubSonic 설치
3. Getting Started
4. SubSonic을 활용한 CRUD 작업 예제
1. SubSonic 이란?
- SubSonice은 닷넷환경에서 활용할 수 있는 ORM 툴의 일종입니다.
닷넷 기반에서 활용할 수 있는 ORM 툴의 종류는 대략 다음과 같습니다.
Open Source
| NHibernate
| - Java 버전인 Hibernate의 닷넷 포팅 버전
- 사용자층이 가장 넓은 정통 ORM 툴
|
iBatis.Net
| - Java 버전인 iBatis의 닷넷 포팅 버전
- Hibernate와 더불어 사용자층이 넓으며 정통
ORM 툴이라기 보다는 Data Mapper에 가까움
- MySpace.com에서 사용됨
|
SubSonic
| - 현재 Linq To Sql 개발팀의 일원인
Rob Connery에 의해 개발됨
- DAO 소스 자동 생산 기능이 뛰어남
|
상용
| EntitySpaces
| - 사용법은 SubSonic과 유사함
|
Microsoft
| Linq To SQL
| - .Net 3.0에서 제공하는 Linq의 일종
|
Entity Framework
| - .Net 3.5 Extension에서 제공
- 테이블과 객체의 맵핑을 통한 정통 ORM
|
- SubSonict과 같은 ORM 툴을 활용하면
1) Data Access 코드를 작성하는데 들이던 시간과 노력을 줄일 수 있습니다.
2) 객체지향적 언어와 관계지향적 DB의 차이에서 오는 여러가지 문제들을 해결할 수 있습니다.
3) ORM 툴에서 제공해주는 쿼리 캐쉬 기능을 사용하여 퍼포먼스를 향상시킬 수 있습니다.
4) 쿼리를 사용할 때보다 코드가 직관적이 되므로 데이터 집중적인 어플리케이션을 제작할 수 있습니다.
5) ORM을 잘 사용하기 위해서는 근본적으로 DB의 정규화가 잘 이루어져서 조직화되어야 하므로 시간이 흘러도 어플리케이션의 일관성을 유지하는데 도움이 됩니다.
- SubSonic은 크게 두가지 기능을 제공합니다. 객체에 대한 질의를 DB에 대한 쿼리로 변경하여 결과값을 반환하는 역할과 DB의 테이블, 프로시져 들과 매칭되는DAO 코드를 자동 생산해주는 기능입니다.
2. SubSonic 설치
- SubSonic의 홈페이지는 http://subsonicproject.com/ 입니다.
2008/7/14일 현재 가장 최신 버전은 SubSonic 2.1 Beta3이며http://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=subsonic&ReleaseId=11591에서 다운받을 수 있습니다.
- “Setup-SubSonic-2.1-Beta3.exe”을 다운로드받은 후에 설치를 시작합니다.
- 설치가 끝났으면 자동 소스 생성 기능을 VS2005에서 사용하기 쉽도록 외부 도구 연결합니다.
1) 메뉴 – 도구 – 외부도구 창을 띄운 후 추가 버튼을 클릭한 후 아래처럼 입력합니다.
- 제목 : &SubSonic DAL
- 명령 : C:\Program Files\SubSonic\SubSonic 2.1 Beta 3\SubCommander\sonic.exe
- 인수 : generate /out Service
- 초기디렉토리 : $(ProjectDir)
- 인수확인 체크박스 체크!
[명령] 항목의 값은 설치 경로에 따라 달라질 수 있습니다. [인수] 항목에서Service는 자동
생산된 코드들이 위치할 폴더입니다.
- 이것으로 SubSonic을 사용할 준비가 끝났습니다.
3. Getting Started
- 설치가 끝났으면 DB에 접속해서 데이터를 가져오는 간단한 어플리케이션을 만들어 보겠습니다. 예제는 윈폼기반 어플리케이션이며, 웹폼도 이와 별반 다르지 않으며 오히려 더욱 간단할 수도 있습니다.
1) “MySubSonic” 이라는 이름으로 윈폼어플리케이션을 만듭니다. DataGridView가 올려진 폼을 하나 만듭니다. 여기에 데이터를 출력하는 간단한 어플리케이션을 만들것입니다.
2) 아래의 라이브러리들을 참조 추가 합니다.
- SubSonic.dll (기본경로에 설치하셨다면 C:\Program Files\SubSonic\SubSonic 2.1 Beta 3\SubSonic 폴더에 있을 것입니다. )
- System.configuratiol
- System.Web (윈폼일지라도 필수적으로 추가해야 합니다.)
3) App.Config를 추가한 후 아래의 내용을 삽입합니다.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="SubSonicService" type="SubSonic.SubSonicSection, SubSonic"requirePermission="false" />
</configSections>
<appSettings/>
<connectionStrings>
<clear />
<add name="AdventureWorks" connectionString="Data Source=(local);Initial Catalog=AdventureWorks;Persist Security Info=True;User ID=dbuserid;Password=dbpassword" />
</connectionStrings>
<SubSonicService defaultProvider="AdventureWorks">
<providers>
<clear/>
<add name="AdventureWorks"
type="SubSonic.SqlDataProvider, SubSonic"
connectionStringName="AdventureWorks"
generatedNamespace="Service"
includeTableList="*"
excludeTableList=""
/>
</providers>
</SubSonicService>
</configuration>
- 여기엔 DB 커넥션 정보가 기재되어 있는데 여기에 기재된 DB의 테이블과 프로시져들을 기반으로 자동 소스 생성 작업이 진행됩니다. SQL Server 2005에서 제공하는 AdventureWorks 데이터베이스를 사용합니다. 위에서 generatedNamespace는 생설될 클래스의 네임스페이스 이름입니다. 여기선 Service 폴더에 생성 시킬것이므로 폴더명과 동일하게 주었습니다.
- AdventureWorks DB는http://www.codeplex.com/MSFTDBProdSamples/Release/ProjectReleases.aspx?ReleaseId=4004 에서 다운받을 수 있습니다.
4) 다음엔 이전에 추가셔켰던 외부 도구로 가셔서 소스 생성만 시키면 됩니다.
5) 확인 버튼을 클릭합니다.
6) DB의 테이블과 프로시져에 대한 소스자동 생성 작업이 시작됩니다.
7) 소스 생성 작업이 끝나면 프로젝트를 선택하여 “모든 파일 표시” 버튼을 클릭한 후 Service 폴더를 “프로젝트에 포함” 시킵니다. 전체 솔루션 빌드 합니다.
8) 각 테이블마다 3개의 클래스가 생성됩니다.
9) 그럼, 폼의 Shown 이벤트에 간단히 테이터를 가져와서 데이터 그리드뷰에 바인딩해 보겠습니다.
10) Form1의 Shown 이벤트에 아래의 소스를 입력합니다. “Product” 는 테이블명입니다. 각자의 DB에 맞는 테이블명을 기재하시면 됩니다.
private void Form1_Shown(object sender, EventArgs e)
{
IDataReader reader = Product.FetchAll();
DataTable dt = new DataTable("Product");
dt.Load(reader);
dataGridView1.DataSource = dt;
}
11) Service 네임스페이스를 using에 추가합니다.
using Service;
12) 위의 과정을 별문제 없이 따라하셨다면 어플리케이션을 실행시킨후 목적하신 테이블의 데이터가 그리드에 바인딩되었을 겁니다. 코드를 보면 아시겠지만, 테이블에 맵핑된 Product 객체를 통해서 간단히 모든 데이터를 가져올 수 있습니다.
4. SubSonic을 활용한 CRUD 작업 예제
4.1 SELECT
- 아래는 SubSonic 웹사이트에서 발췌한 것으로서 SELECT 형태의 쿼리에 사용할 수 있는 다양한 방법들을 소개하고 있습니다.
- Simple Select with string columns
int records = new Select("productID").
From("Products").GetRecordCount();
- Simple Select with typed columns
int records = new Select(Product.ProductIDColumn, Product.ProductNameColumn).
From<Product>().GetRecordCount();
- Returning a Single object
Product p = new Select().From<Product>().
Where("ProductID").IsEqualTo(1).ExecuteSingle<Product>();
- Returning all columns
int records = new Select().From("Products").GetRecordCount();
- Simple Where
int records = new Select().From("Products").
Where("categoryID").IsEqualTo(5).GetRecordCount();
- Simple Where with And (as Collection)
ProductCollection products =
DB.Select().From("Products")
.Where("categoryID").IsEqualTo(5)
.And("productid").IsGreaterThan(50)
.ExecuteAsCollection<ProductCollection>();
- Simple Inner Join
SubSonic.SqlQuery q = new Select("productid").From(OrderDetail.Schema)
.InnerJoin(Product.Schema)
.Where("CategoryID").IsEqualTo(5);
- Simple Join With Table Enum
SubSonic.SqlQuery q = new Select().From(Tables.OrderDetail)
.InnerJoin(Tables.Product)
.Where("CategoryID").IsEqualTo(5);
- Multiple Joins As Collection
CustomerCollection customersByCategory = new Select()
.From(Customer.Schema)
.InnerJoin(Order.Schema)
.InnerJoin(OrderDetail.OrderIDColumn, Order.OrderIDColumn)
.InnerJoin(Product.ProductIDColumn, OrderDetail.ProductIDColumn)
.Where("CategoryID").IsEqualTo(5)
.ExecuteAsCollection<CustomerCollection>();
- Left Outer Join With Generics
SubSonic.SqlQuery query = DB.Select(Aggregate.GroupBy("CompanyName"))
.From<Customer>()
.LeftOuterJoin<Order>();
- Left Outer Join With Schema
SubSonic.SqlQuery query = DB.Select(Aggregate.GroupBy("CompanyName"))
.From(Customer.Schema)
.LeftOuterJoin(Order.CustomerIDColumn, Customer.CustomerIDColumn);
- Left Outer Join With Magic Strings
SubSonic.SqlQuery query = DB.Select(Aggregate.GroupBy("CompanyName"))
.From("Customers")
.LeftOuterJoin("Orders");
- Simple Select With Collection Result
ProductCollection p = Select.AllColumnsFrom<Product>()
.ExecuteAsCollection<ProductCollection>();
- Simple Select With LIKE
ProductCollection p = DB.Select()
.From(Product.Schema)
.InnerJoin(Category.Schema)
.Where("CategoryName").Like("c%")
.ExecuteAsCollection<ProductCollection>();
- Using Nested Where/And/Or
ProductCollection products = Select.AllColumnsFrom<Product>()
.WhereExpression("categoryID").IsEqualTo(5).And("productid").IsGreaterThan(10)
.OrExpression("categoryID").IsEqualTo(2).And("productID").IsBetweenAnd(2, 5)
.ExecuteAsCollection<ProductCollection>();
ProductCollection products = Select.AllColumnsFrom<Product>()
.WhereExpression("categoryID").IsEqualTo(5).And("productid").IsGreaterThan(10)
.Or("categoryID").IsEqualTo(2).AndExpression("productID").IsBetweenAnd(2, 5)
.ExecuteAsCollection<ProductCollection>();
- Simple Paged Query
SubSonic.SqlQuery q = Select.AllColumnsFrom<Product>().
Paged(1, 20).Where("productid").IsLessThan(100);
- Paged Query With Join
SubSonic.SqlQuery q = new Select("ProductId", "ProductName", "CategoryName").
From("Products").InnerJoin(Category.Schema).Paged(1, 20);
- Paged View
SubSonic.SqlQuery q = new Select().From(Invoice.Schema).Paged(1, 20);
- Simple IN Query
int records = new Select().From(Product.Schema)
.Where("productid").In(1, 2, 3, 4, 5)
.GetRecordCount();
- Using IN With Nested Select
int records = Select.AllColumnsFrom<Product>()
.Where("productid")
.In(
new Select("productid").From(Product.Schema)
.Where("categoryid").IsEqualTo(5)
)
.GetRecordCount();Using Multiple INs
SubSonic.SqlQuery query = new Select()
.From(Product.Schema)
.Where(Product.CategoryIDColumn).In(2)
.And(Product.SupplierIDColumn).In(3);
4.2 INSERT
- 데이터를 입력하는 여러가지 방법을 지원하지만 아래의 두가지 방법이 자주 사용됩니다.
// #1 – 테이블과 1:1 맵핑된 클래스를 이용하는 방법
UserInfo u = new UserInfo();
u.Id = "사용자아이디";
u.KrNm = "사용자이름";
u.Save();
// #2 – Insert 클래스를 이용하는 방법
DB.Insert()
.Into(UserInfo.Schema, new string[] { "ID", "KR_NM" })
.Values("사용자아이디", "사용자이름")
.Execute();
4.3 UPDATE
- 데이터를 수정하는 방법은 여러가지를 제공하지만 아래의 방법이 자주 사용됩니다.
SqlQuery qry = new Update(UserInfo.Schema)
.Set(UserInfo.KrNmColumn.ColumnName).EqualTo("노홍철")
.Where(UserInfo.IdColumn.ColumnName).IsEqualTo("22401");
int row = qry.Execute();
4.4 DELETE
- 데이터를 삭제하는 방법도 여러가지 제공하지만 아래의 방법이 자주 사용됩니다.
SqlQuery qry = new Delete(UserInfo.Schema)
.Where(UserInfo.IdColumn.ColumnName).IsEqualTo("22401");
int row = qry.Execute();