파트 4: 모델과 데이터 접근
- 본 번역문서의 원문은 Part 4: Models and Data Access www.asp.net 입니다.
- 본 번역문서는 ASP.NET MVC 예제 - MVC 뮤직 스토어 (II) www.taeyo.net 에서도 함께 제공됩니다.
MVC 뮤직 스토어 응용 프로그램은 ASP.NET MVC와 Visual Studio for Web Development를 소개하고, 그 사용법을 단계별로 살펴보기 위한 자습용 응용 프로그램으로, 온라인 음반 판매 기능을 비롯하여, 기초적인 사이트 관리, 사용자 로그인, 장바구니 기능 등이 구현된 간단한 전자상거래 사이트 예제입니다.
본 자습서 시리즈에서는 ASP.NET MVC 뮤직 스토어 응용 프로그램을 구축하기 위해서 필요한 모든 단계들을 자세하게 살펴볼 것입니다.
이번 파트 4에서는 모델 및 데이터 접근에 관해서 살펴봅니다.
지금까지는 컨트롤러에서 뷰 템플릿으로 "가상 데이터"만 전달했었습니다. 이제는 실제 데이터를 연결시킬 준비가 되었습니다. 본 자습서에서는 데이터베이스 엔진으로 Server Compact Edition을 (SQL CE라고도 합니다) 사용하는 방법을 살펴볼 것입니다. SQL CE는 내장된 파일 기반의 무료 데이터베이스로, 설치나 구성이 필요 없으며, 로컬 개발에 매우 편리합니다.
Entity Framework Code-First를 이용한 데이터 접근
본 자습서에서는 데이터베이스를 질의하거나 수정하기 위한 방식으로 ASP.NET MVC 3 프로젝트에 내장되어 있는 Entity Framework (EF) 지원을 사용해보려고 합니다. Entity Framework는 유연한 객체 관계 매핑(ORM, Object Relational Mapping) 데이터 API로, 개체 지향적인 방식으로 데이터베이스에 저장되어 있는 데이터들을 질의하거나 수정할 수 있습니다.
Entity Framework 버전 4에서는 Code-First라는 이름의 개발 패러다임이 지원됩니다. Code-First를 사용하면 간단한 클래스("plain-Old CLR Objects"의 약자인 POCO로 알려진)로 모델 개체를 생성할 수 있으며, 이 클래스들로부터 실시간으로 데이터베이스를 생성할 수도 있습니다.
모델 클래스 변경하기
본 자습서에서는 Entity Framework의 데이터베이스 생성 기능을 이용해보려고 합니다. 그러나, 그 전에 먼저 모델 클래스를 약간 수정해서 추후에 이용하게 될 부분들을 추가해줘야 합니다.
Artist 모델 클래스 추가하기
이전 파트에서 작성했던 Albums 모델은 앞으로 아티스트 정보와 연결될 것이므로, 아티스트를 표현할 간단한 모델 클래스를 추가해야 합니다. 따라서, Models 폴더에 Artist.cs라는 이름의 새로운 클래스를 추가하고, 다음과 같은 코드를 작성합니다.
namespace MvcMusicStore.Models { public class Artist { public int ArtistId { get; set; } public string Name { get; set; } } }
기존 모델 클래스 수정하기
먼저, Album 클래스를 다음과 같이 수정합니다.
namespace MvcMusicStore.Models { public class Album { public int AlbumId { get; set; } public int GenreId { get; set; } public int ArtistId { get; set; } public string Title { get; set; } public decimal Price { get; set; } public string AlbumArtUrl { get; set; } public Genre Genre { get; set; } public Artist Artist { get; set; } } }
그런 다음, Genre 클래스를 다음과 같이 수정합니다.
using System.Collections.Generic; namespace MvcMusicStore.Models { public partial class Genre { public int GenreId { get; set; } public string Name { get; set; } public string Description { get; set; } public List<Album> Albums { get; set; } } }
App_Data 폴더 추가하기
그러면 이번에는 프로젝트에 SQL Server Express 데이터베이스 파일을 담기 위한 App_Data 폴더를 추가해보도록 하겠습니다. App_Data 폴더는 ASP.NET의 특수 디렉터리로, 데이터베이스에 접근하기 위해서 필요한 적절한 보안 접근 권한을 기본적으로 갖고 있습니다. "Project" 메뉴에서 "Add ASP.NET Folder" > "App_Data"를 선택합니다.
web.config 파일에 연결 문자열 생성하기
Entity Framework가 데이터베이스에 연결할 수 있는 방법을 인식할 수 있도록 웹사이트의 구성 파일에 설정을 몇 라인 추가해보겠습니다. 프로젝트의 루트에 위치한 Web.config 파일을 마우스로 더블 클릭해서 엽니다.
파일 하단으로 스크롤해서 내린 다음, 가장 마지막 라인 바로 위에 다음과 같은 <connectionStrings> 섹션을 추가합니다.
<connectionStrings> <add name="MusicStoreEntities" connectionString="Data Source=|DataDirectory|MvcMusicStore.sdf" providerName="System.Data.SqlServerCe.4.0"/> </connectionStrings> </configuration>
컨텍스트 클래스 추가하기
마우스 오른쪽 버튼으로 Models 폴더를 클릭해서 MusicStoreEntities.cs라는 새로운 클래스를 추가합니다.
이 클래스는 Entity Framework 데이터베이스 컨텍스트를 나타내며, 생성, 조회, 수정, 삭제 작업을 처리해줍니다. 이 클래스의 코드는 다음과 같습니다.
using System.Data.Entity; namespace MvcMusicStore.Models { public class MusicStoreEntities : DbContext { public DbSet<Album> Albums { get; set; } public DbSet<Genre> Genres { get; set; } } }
이것이 필요한 작업의 전부입니다. 별도의 구성이나 특별한 인터페이스 등을 구현한 필요도 전혀 없습니다. 그저, DbContext 기본 클래스를 확장하기만 하면, MusicStoreEntities 클래스가 데이터베이스 작업을 대신 처리해줍니다. 이제 데이터베이스를 연결했으므로, 모델 클래스에 몇 가지 속성을 추가해서 데이터베이스로부터 일부 추가적인 정보들의 이점을 얻도록 하겠습니다.
뮤직 스토어 카탈로그 데이터 추가하기
본 자습서에서는 새롭게 생성되는 데이터베이스에 "초기(Seed)" 데이터를 추가해주는 Entity Framework의 기능을 활용해보고자 합니다. 이 기능을 활용해서 뮤직 스토어 카탈로그에 장르들의 목록, 아티스트, 음반 정보들을 미리 채워넣게 될 것입니다. 본 자습서의 이전 파트에서 사이트의 디자인 관련 파일들을 가져오기 위해서 다운로드 받았던 MvcMusicStore-Assets.zip 파일의 Code 폴더 하위에 이 초기 데이터를 추가해주는 클래스가 포함되어 있습니다.
이 파일에 포함된 Code/Models 폴더 하위에 위치한 SampleData.cs 파일을 다음 그림과 같이 드래그해서 MVC 뮤직 스토어 프로젝트의 Models 폴더에 드랍시킵니다.
그런 다음, Entity Framework가 이 SampleData 클래스를 인식할 수 있도록 코드를 한 라인 추가해줘야 합니다. 프로젝트의 루트에서 Global.asax 파일을 더블 클릭해서 연 다음, Application_Start 메서드의 상단에 다음과 같은 코드를 추가합니다.
protected void Application_Start() { System.Data.Entity.Database.SetInitializer(new MvcMusicStore.Models.SampleData()); AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); }
이제, 프로젝트에서 Entity Framework를 구성하기 위해 필요한 모든 작업들이 마무리 되었습니다.
데이터베이스 질의하기
이제, "가상 데이터"를 사용하는 대신, 모든 정보들을 데이터베이스 호출을 통해서 질의하도록 StoreController 클래스를 변경해보겠습니다. 먼저, 다음 코드와 같이 StoreController 클래스에 MusicStoreEntities 클래스의 인스턴스를 담을 storeDB라는 이름의 필드를 선언합니다:
public class StoreController : Controller { MusicStoreEntities storeDB = new MusicStoreEntities();
데이터베이스에 질의하도록 Store 컨트롤러의 Index 메서드 변경하기
이 MusicStoreEntities 클래스는 Entity Framework에 의해서 관리되며, 데이터베이스의 테이블들에 대한 컬렉션 속성들을 노출해줍니다. 데이터베이스에서 모든 장르들의 목록을 가져오도록 StoreController 클래스의 Index 메서드를 수정해보겠습니다. 기존에는 하드코딩 된 문자열 데이터를 이용해서 이 작업을 처리했지만, 지금부터는 Entity Framework 컨텍스트의 Generes 컬렉션을 대신 사용할 수 있습니다:
public ActionResult Index() { var genres = storeDB.Genres.ToList(); return View(genres); }
뷰 템플릿은 변경할 필요가 전혀 없는데, 지금까지 반환해왔던 동일한 뷰 모델을 앞으로도 계속 반환할 것이기 때문입니다. 그저 데이터베이스에서 가져온 실제 데이터를 반환하기만 하면 됩니다.
프로젝트를 다시 실행시킨 다음, "/Store" URL로 이동해보면, 이제 데이터베이스에서 가져온 장르들의 목록이 나타나는 것을 볼 수 있을 것입니다:
실제 데이터를 사용하도록 Store 컨트롤러의 Browse 메서드와 Details 메서드 변경하기
MVC 뮤직 스토어에서는 이름을 기준으로 특정 장르를 검색하기 위해서 /Store/Browse?genre=[특정 장르] 액션 메서드를 이용하고 있습니다. 동일한 장르 이름을 가진 항목이 여러 개 존재할 수는 없으므로, 단 하나의 장르만 반환되어야 하는데, 다음 코드와 같이 LINQ의 .Single() 메서드를 사용하면 적절한 Genre 개체를 조회할 수 있습니다. (아직 이 코드를 작성하지는 마십시요.):
var example = storeDB.Genres.Single(g => g.Name == “Disco”);
이 예제 코드에 사용된 Single 메서드는 람다식을 매개변수로 받아서, 지정된 값과 일치하는 이름을 갖고 있는 단일 Genre 개체를 반환합니다. 결국, 이 코드는 Name 속성값이 Disco인 단일 Genre 개체를 로딩하게 됩니다.
그리고, Genre 개체를 가져올 때, 함께 로드할 다른 관련 엔티티들을 지정할 수 있는 Entity Framework의 기능을 활용해보겠습니다. 이 기능은 Query Result Shaping이라고 부르며, 필요한 모든 정보들을 가져오기 위해서 데이터베이스에 접근해야 될 횟수를 줄여줍니다. 가령, 이 예제에서는 조회한 장르에 대한 음반 정보들까지 미리 가져오고자 하므로, Genres.Include("Albums")가 포함되도록 질의를 변경해서 관련된 음반 정보들까지 가져오도록 만듭니다. 장르와 음반의 데이터를 단일 데이터베이스 요청만으로 모두 가져오므로, 이 방법이 훨씬 효과적입니다.
장황한 설명은 일단 생략하도록 하겠습니다. 다음은 수정된 Browse 컨트롤러 액션의 모습입니다:
public ActionResult Browse(string genre) { // Retrieve Genre and its Associated Albums from database var genreModel = storeDB.Genres.Include("Albums") .Single(g => g.Name == genre); return View(genreModel); }
이제 각 장르에 포함된 음반들을 출력하도록 Store 영역의 Browse 뷰를 변경할 수 있습니다. 뷰 템플릿을 연 다음 (/Views/Store/Browse.cshtml), 다음과 같이 음반들의 목록을 출력하기 위한 코드를 추가합니다.
@model MvcMusicStore.Models.Genre @{ ViewBag.Title = "Browse"; } <h2>Browsing Genre: @Model.Name</h2> <ul> @foreach (var album in Model.Albums) { <li> @album.Title </li> } </ul>
다시 응용 프로그램을 시작시킨 다음, /Store/Browse?genre=Jazz로 이동해보면, 데이터베이스로부터 결과가 조회되어, 선택된 장르에 해당하는 모든 앨범들이 나타날 것입니다.
지금까지 처리한 작업과 동일한 작업을 /Store/Details/[id] URL을 대상으로도 수행해서, 가상 데이터를 매개변수 값과 일치하는 음반 정보를 로드하는 데이터베이스 질의로 대체합니다.
public ActionResult Details(int id) { var album = storeDB.Albums.Find(id); return View(album); }
그리고, 응용 프로그램을 실행시킨 다음, /Store/Details/1로 이동해보면 데이터베이스로부터 조회해 온 결과가 나타날 것입니다.
이제, 음반의 ID를 기준으로 음반 정보를 출력할 수 있도록 Store 영역의 Details 페이지의 준비가 마무리되었으므로, Browse 뷰를 수정해서 Details 뷰에 링크를 걸 수 있게 만듭니다. 이전 파트의 마지막 부분에서, Index 페이지에서 Browse 페이지로 링크를 걸 때 사용했던 바로 그 Html.ActionLink 메서드를 다시 사용합니다. 변경이 마무리된 Browse 뷰의 완전한 소스는 다음과 같습니다.
@model MvcMusicStore.Models.Genre @{ ViewBag.Title = "Browse"; } <h2>Browsing Genre: @Model.Name</h2> <ul> @foreach (var album in Model.Albums) { <li> @Html.ActionLink(album.Title, "Details", new { id = album.AlbumId }) </li> } </ul>
이제 MVC 뮤직 스토어의 메인 페이지에서, 특정 장르의 음반 목록을 제공해주는 장르 페이지로 이동할 수 있고, 다시 이 페이지에서 음반 이름을 클릭하여 특정 음반의 상세 정보를 살펴볼 수 있는 상세 페이지로 이동할 수 있습니다.
질문이나 의견이 있으시면 http://mvcmusicstore.codeplex.com/을 방문해주시기 바랍니다.
- 파트 1: 개요 및 프로젝트 생성하기 2012-07-16 11:33
- 파트 2: 컨트롤러 2012-07-16 13:34
- 파트 3: 뷰와 뷰 모델 2012-07-23 13:34
- 파트 4: 모델과 데이터 접근 2012-07-23 13:34
- 파트 5: 폼 편집하기 및 템플릿 사용하기 2012-08-05 13:34
- 파트 6: 데이터 어노테이션을 사용하여 모델 유효성 검사하기 2012-08-05 13:34
- 파트 7: 멤버십과 권한 2012-08-17 13:34
- 파트 8: 장바구니와 Ajax 업데이트 2012-08-17 13:34
- 파트 9: 등록 및 결제 2012-10-15 13:35
- 파트 10: 탐색 및 사이트 디자인 최종 수정, 결론 2012-10-15 13:35