다음을 통해 공유


데이터 액세스 레이어 만들기

작성자: Erik Reitan

이 자습서 시리즈에서는 웹용 ASP.NET 4.5 및 Microsoft Visual Studio Express 2013을 사용하여 ASP.NET Web Forms 애플리케이션을 빌드하는 기본 사항을 설명합니다. C# 소스 코드가 있는 Visual Studio 2013 프로젝트는 이 자습서 시리즈와 함께 사용할 수 있습니다.

이 자습서에서는 ASP.NET Web Forms 및 Entity Framework Code First를 사용하여 데이터베이스에서 데이터를 만들고, 액세스하고, 검토하는 방법을 설명합니다. 이 자습서는 이전 자습서 "프로젝트 만들기"를 기반으로 하며 Wingtip Toy Store 자습서 시리즈의 일부입니다. 이 자습서를 완료하면 프로젝트의 Models 폴더에 있는 데이터 액세스 클래스 그룹을 빌드하게 됩니다.

학습할 내용:

  • 데이터 모델을 만드는 방법
  • 데이터베이스를 초기화하고 시드하는 방법입니다.
  • 데이터베이스를 지원하도록 애플리케이션을 업데이트하고 구성하는 방법입니다.

자습서에 도입된 기능은 다음과 같습니다.

  • Entity Framework Code First
  • LocalDB
  • 데이터 주석

데이터 모델 만들기

Entity Framework 는 ORM(개체 관계형 매핑) 프레임워크입니다. 관계형 데이터를 개체로 사용할 수 있으므로 일반적으로 작성해야 하는 대부분의 데이터 액세스 코드를 제거할 수 있습니다. Entity Framework를 사용하여 LINQ를 사용하여 쿼리를 실행한 다음 강력한 형식의 개체로 데이터를 검색하고 조작할 수 있습니다. LINQ는 데이터를 쿼리하고 업데이트하기 위한 패턴을 제공합니다. Entity Framework를 사용하면 데이터 액세스 기본 사항에 집중하지 않고 애플리케이션의 나머지 부분을 만드는 데 집중할 수 있습니다. 이 자습서 시리즈의 뒷부분에서는 데이터를 사용하여 탐색 및 제품 쿼리를 채우는 방법을 보여 줍니다.

Entity Framework는 Code First라는 개발 패러다임을 지원합니다. Code First를 사용하면 클래스를 사용하여 데이터 모델을 정의할 수 있습니다. 클래스는 기타 형식, 메서드 및 이벤트의 변수를 그룹화하여 자체 사용자 지정 형식을 만들 수 있는 구문입니다. 클래스를 기존 데이터베이스에 매핑하거나 이를 사용하여 데이터베이스를 생성할 수 있습니다. 이 자습서에서는 데이터 모델 클래스를 작성하여 데이터 모델을 만듭니다. 그런 다음 Entity Framework가 이러한 새 클래스에서 즉시 데이터베이스를 만들도록 합니다.

먼저 Web Forms 애플리케이션의 데이터 모델을 정의하는 엔터티 클래스를 만듭니다. 그런 다음 엔터티 클래스를 관리하고 데이터베이스에 대한 데이터 액세스를 제공하는 컨텍스트 클래스를 만듭니다. 데이터베이스를 채우는 데 사용할 이니셜라이저 클래스도 만듭니다.

Entity Framework 및 참조

기본적으로 Entity Framework는 Web Forms 템플릿을 사용하여 새 ASP.NET 웹 애플리케이션을 만들 때 포함됩니다. Entity Framework를 NuGet 패키지로 설치, 제거 및 업데이트할 수 있습니다.

이 NuGet 패키지에는 프로젝트 내에서 다음 런타임 어셈블리가 포함됩니다.

  • EntityFramework.dll – Entity Framework에서 사용하는 모든 공용 런타임 코드
  • EntityFramework.SqlServer.dll – Entity Framework용 Microsoft SQL Server 공급자

엔터티 클래스

데이터의 스키마를 정의하기 위해 만드는 클래스를 엔터티 클래스라고 합니다. 데이터베이스 디자인을 새로운 경우 엔터티 클래스를 데이터베이스의 테이블 정의로 간주합니다. 클래스의 각 속성은 데이터베이스 테이블의 열을 지정합니다. 이러한 클래스는 개체 지향 코드와 데이터베이스의 관계형 테이블 구조 간에 간단한 개체 관계형 인터페이스를 제공합니다.

이 자습서에서는 제품 및 범주에 대한 스키마를 나타내는 간단한 엔터티 클래스를 추가하여 시작합니다. 제품 클래스에는 각 제품에 대한 정의가 포함됩니다. 제품 클래스ProductID의 각 멤버 이름은 , , ProductName, DescriptionImagePath, UnitPrice, CategoryID및 입니다Category. 범주 클래스에는 자동차, 보트 또는 평면과 같이 제품이 속할 수 있는 각 범주에 대한 정의가 포함됩니다. 범주 클래스의 각 멤버 이름은 , , CategoryNameDescriptionProducts입니다CategoryID. 각 제품은 범주 중 하나에 속합니다. 이러한 엔터티 클래스는 프로젝트의 기존 Models 폴더에 추가됩니다.

  1. 솔루션 탐색기Models 폴더를 마우스 오른쪽 단추로 클릭한 다음 추가 ->새 항목을 선택합니다.

    Models 폴더가 강조 표시되고 드롭다운 메뉴 추가 및 새 항목이 선택된 솔루션 탐색기 창의 스크린샷

    새 항목 추가 대화 상자가 표시됩니다.

  2. 왼쪽의 설치된 창에서 Visual C#에서 코드를 선택합니다.

    Visual C#이 열려 있고 코드가 선택된 왼쪽에 설치된 창을 보여 주는 새 항목 추가 창의 스크린샷

  3. 가운데 창에서 클래스 를 선택하고 이 새 클래스의 이름을 Product.cs로 지정합니다.

  4. 추가를 클릭합니다.
    새 클래스 파일이 편집기에서 표시됩니다.

  5. 기본 코드를 다음 코드로 바꿉니다.

    using System.ComponentModel.DataAnnotations;
    
    namespace WingtipToys.Models
    {
        public class Product
        {
            [ScaffoldColumn(false)]
            public int ProductID { get; set; }
    
            [Required, StringLength(100), Display(Name = "Name")]
            public string ProductName { get; set; }
    
            [Required, StringLength(10000), Display(Name = "Product Description"), DataType(DataType.MultilineText)]
            public string Description { get; set; }
    
            public string ImagePath { get; set; }
    
            [Display(Name = "Price")]
            public double? UnitPrice { get; set; }
    
            public int? CategoryID { get; set; }
    
            public virtual Category Category { get; set; }
        }
    }
    
  6. 그러나 1~4단계를 반복하여 다른 클래스를 만듭니다. 그러나 새 클래스의 이름을 Category.cs 로 지정하고 기본 코드를 다음 코드로 바꿉니다.

    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    
    namespace WingtipToys.Models
    {
        public class Category
        {
            [ScaffoldColumn(false)]
            public int CategoryID { get; set; }
    
            [Required, StringLength(100), Display(Name = "Name")]
            public string CategoryName { get; set; }
    
            [Display(Name = "Product Description")]
            public string Description { get; set; }
    
            public virtual ICollection<Product> Products { get; set; }
        }
    }
    

앞에서 설명한 Category 것처럼 클래스는 애플리케이션이 판매하도록 설계된 제품 유형(예: "자동차", "보트", "로켓" 등)을 나타내며 Product 클래스는 데이터베이스의 개별 제품(장난감)을 나타냅니다. 개체의 각 instance 관계형 데이터베이스 테이블 내의 Product 행에 해당하며 Product 클래스의 각 속성은 관계형 데이터베이스 테이블의 열에 매핑됩니다. 이 자습서의 뒷부분에서는 데이터베이스에 포함된 제품 데이터를 검토합니다.

데이터 주석

클래스의 특정 멤버에는 와 같은 [ScaffoldColumn(false)]멤버에 대한 세부 정보를 지정하는 특성이 있음을 알 수 있습니다. 데이터 주석입니다. 데이터 주석 특성은 해당 멤버에 대한 사용자 입력의 유효성을 검사하고, 해당 멤버에 대한 서식을 지정하고, 데이터베이스를 만들 때 모델링되는 방법을 지정하는 방법을 설명할 수 있습니다.

Context 클래스

데이터 액세스에 클래스 사용을 시작하려면 컨텍스트 클래스를 정의해야 합니다. 앞에서 설명한 것처럼 컨텍스트 클래스는 엔터티 클래스(예: Product 클래스 및 Category 클래스)를 관리하고 데이터베이스에 대한 데이터 액세스를 제공합니다.

이 절차에서는 Models 폴더에 새 C# 컨텍스트 클래스를 추가합니다.

  1. Models 폴더를 마우스 오른쪽 단추로 클릭한 다음 추가 ->새 항목을 선택합니다.
    새 항목 추가 대화 상자가 표시됩니다.

  2. 가운데 창에서 클래스 를 선택하고 이름을 ProductContext.cs 로 지정하고 추가를 클릭합니다.

  3. 클래스에 포함된 기본 코드를 다음 코드로 바꿉다.

    using System.Data.Entity;
    namespace WingtipToys.Models
    {
        public class ProductContext : DbContext
        {
            public ProductContext() : base("WingtipToys")
            {
            }
            public DbSet<Category> Categories { get; set; }
            public DbSet<Product> Products { get; set; }
        }
    }
    

이 코드는 강력한 형식의 개체를 사용하여 데이터를 쿼리, 삽입, 업데이트 및 삭제하는 기능을 포함하는 Entity Framework의 모든 핵심 기능에 액세스할 수 있도록 네임스페이스를 추가 System.Data.Entity 합니다.

클래스는 ProductContext 데이터베이스의 클래스 인스턴스 가져오기, 저장 및 업데이트를 Product 처리하는 Entity Framework 제품 데이터베이스 컨텍스트를 나타냅니다. 클래스는 ProductContext Entity Framework에서 DbContext 제공하는 기본 클래스에서 파생됩니다.

이니셜라이저 클래스

컨텍스트를 처음 사용할 때 데이터베이스를 초기화하려면 몇 가지 사용자 지정 논리를 실행해야 합니다. 이렇게 하면 제품 및 범주를 즉시 표시할 수 있도록 시드 데이터를 데이터베이스에 추가할 수 있습니다.

이 절차에서는 Models 폴더에 새 C# 이니셜라이저 클래스를 추가합니다.

  1. Models 폴더에 다른 Class 을 만들고 이름을 ProductDatabaseInitializer.cs로 지정합니다.

  2. 클래스에 포함된 기본 코드를 다음 코드로 바꿉다.

    using System.Collections.Generic;
    using System.Data.Entity;
    
    namespace WingtipToys.Models
    {
      public class ProductDatabaseInitializer : DropCreateDatabaseIfModelChanges<ProductContext>
      {
        protected override void Seed(ProductContext context)
        {
          GetCategories().ForEach(c => context.Categories.Add(c));
          GetProducts().ForEach(p => context.Products.Add(p));
        }
    
        private static List<Category> GetCategories()
        {
          var categories = new List<Category> {
                    new Category
                    {
                        CategoryID = 1,
                        CategoryName = "Cars"
                    },
                    new Category
                    {
                        CategoryID = 2,
                        CategoryName = "Planes"
                    },
                    new Category
                    {
                        CategoryID = 3,
                        CategoryName = "Trucks"
                    },
                    new Category
                    {
                        CategoryID = 4,
                        CategoryName = "Boats"
                    },
                    new Category
                    {
                        CategoryID = 5,
                        CategoryName = "Rockets"
                    },
                };
    
          return categories;
        }
    
        private static List<Product> GetProducts()
        {
          var products = new List<Product> {
                    new Product
                    {
                        ProductID = 1,
                        ProductName = "Convertible Car",
                        Description = "This convertible car is fast! The engine is powered by a neutrino based battery (not included)." + 
                                      "Power it up and let it go!", 
                        ImagePath="carconvert.png",
                        UnitPrice = 22.50,
                        CategoryID = 1
                   },
                    new Product 
                    {
                        ProductID = 2,
                        ProductName = "Old-time Car",
                        Description = "There's nothing old about this toy car, except it's looks. Compatible with other old toy cars.",
                        ImagePath="carearly.png",
                        UnitPrice = 15.95,
                         CategoryID = 1
                   },
                    new Product
                    {
                        ProductID = 3,
                        ProductName = "Fast Car",
                        Description = "Yes this car is fast, but it also floats in water.",
                        ImagePath="carfast.png",
                        UnitPrice = 32.99,
                        CategoryID = 1
                    },
                    new Product
                    {
                        ProductID = 4,
                        ProductName = "Super Fast Car",
                        Description = "Use this super fast car to entertain guests. Lights and doors work!",
                        ImagePath="carfaster.png",
                        UnitPrice = 8.95,
                        CategoryID = 1
                    },
                    new Product
                    {
                        ProductID = 5,
                        ProductName = "Old Style Racer",
                        Description = "This old style racer can fly (with user assistance). Gravity controls flight duration." + 
                                      "No batteries required.",
                        ImagePath="carracer.png",
                        UnitPrice = 34.95,
                        CategoryID = 1
                    },
                    new Product
                    {
                        ProductID = 6,
                        ProductName = "Ace Plane",
                        Description = "Authentic airplane toy. Features realistic color and details.",
                        ImagePath="planeace.png",
                        UnitPrice = 95.00,
                        CategoryID = 2
                    },
                    new Product
                    {
                        ProductID = 7,
                        ProductName = "Glider",
                        Description = "This fun glider is made from real balsa wood. Some assembly required.",
                        ImagePath="planeglider.png",
                        UnitPrice = 4.95,
                        CategoryID = 2
                    },
                    new Product
                    {
                        ProductID = 8,
                        ProductName = "Paper Plane",
                        Description = "This paper plane is like no other paper plane. Some folding required.",
                        ImagePath="planepaper.png",
                        UnitPrice = 2.95,
                        CategoryID = 2
                    },
                    new Product
                    {
                        ProductID = 9,
                        ProductName = "Propeller Plane",
                        Description = "Rubber band powered plane features two wheels.",
                        ImagePath="planeprop.png",
                        UnitPrice = 32.95,
                        CategoryID = 2
                    },
                    new Product
                    {
                        ProductID = 10,
                        ProductName = "Early Truck",
                        Description = "This toy truck has a real gas powered engine. Requires regular tune ups.",
                        ImagePath="truckearly.png",
                        UnitPrice = 15.00,
                        CategoryID = 3
                    },
                    new Product
                    {
                        ProductID = 11,
                        ProductName = "Fire Truck",
                        Description = "You will have endless fun with this one quarter sized fire truck.",
                        ImagePath="truckfire.png",
                        UnitPrice = 26.00,
                        CategoryID = 3
                    },
                    new Product
                    {
                        ProductID = 12,
                        ProductName = "Big Truck",
                        Description = "This fun toy truck can be used to tow other trucks that are not as big.",
                        ImagePath="truckbig.png",
                        UnitPrice = 29.00,
                        CategoryID = 3
                    },
                    new Product
                    {
                        ProductID = 13,
                        ProductName = "Big Ship",
                        Description = "Is it a boat or a ship. Let this floating vehicle decide by using its " + 
                                      "artifically intelligent computer brain!",
                        ImagePath="boatbig.png",
                        UnitPrice = 95.00,
                        CategoryID = 4
                    },
                    new Product
                    {
                        ProductID = 14,
                        ProductName = "Paper Boat",
                        Description = "Floating fun for all! This toy boat can be assembled in seconds. Floats for minutes!" + 
                                      "Some folding required.",
                        ImagePath="boatpaper.png",
                        UnitPrice = 4.95,
                        CategoryID = 4
                    },
                    new Product
                    {
                        ProductID = 15,
                        ProductName = "Sail Boat",
                        Description = "Put this fun toy sail boat in the water and let it go!",
                        ImagePath="boatsail.png",
                        UnitPrice = 42.95,
                        CategoryID = 4
                    },
                    new Product
                    {
                        ProductID = 16,
                        ProductName = "Rocket",
                        Description = "This fun rocket will travel up to a height of 200 feet.",
                        ImagePath="rocket.png",
                        UnitPrice = 122.95,
                        CategoryID = 5
                    }
                };
    
          return products;
        }
      }
    }
    

위의 코드에서 볼 수 있듯이 데이터베이스를 만들고 초기화하면 속성이 재정의 Seed 되고 설정됩니다. 속성이 Seed 설정되면 범주 및 제품의 값을 사용하여 데이터베이스를 채웁니다. 데이터베이스를 만든 후 위의 코드를 수정하여 시드 데이터를 업데이트하려고 하면 웹 애플리케이션을 실행할 때 업데이트가 표시되지 않습니다. 위의 코드는 클래스의 DropCreateDatabaseIfModelChanges 구현을 사용하여 시드 데이터를 다시 설정하기 전에 모델(스키마)이 변경되었는지 여부를 인식하기 때문입니다. 및 Product 엔터티 클래스를 Category 변경하지 않으면 데이터베이스가 시드 데이터로 다시 초기화되지 않습니다.

참고

애플리케이션을 실행할 때마다 데이터베이스를 다시 만들려면 클래스 대신 클래스를 DropCreateDatabaseAlwaysDropCreateDatabaseIfModelChanges 사용할 수 있습니다. 그러나 이 자습서 시리즈의 경우 클래스를 DropCreateDatabaseIfModelChanges 사용합니다.

이 자습서의 이 시점에서 4개의 새 클래스와 1개의 기본 클래스가 있는 Models 폴더가 있습니다.

데이터 액세스 계층 만들기 - Models 폴더

데이터 모델을 사용하도록 애플리케이션 구성

이제 데이터를 나타내는 클래스를 만들었으므로 클래스를 사용하도록 애플리케이션을 구성해야 합니다. Global.asax 파일에서 모델을 초기화하는 코드를 추가합니다. Web.config 파일에서 새 데이터 클래스로 표시되는 데이터를 저장하는 데 사용할 데이터베이스를 애플리케이션에 알려주는 정보를 추가합니다. Global.asax 파일을 사용하여 애플리케이션 이벤트 또는 메서드를 처리할 수 있습니다. Web.config파일을 사용하면 ASP.NET 웹 애플리케이션의 구성을 제어할 수 있습니다.

Global.asax 파일 업데이트

애플리케이션이 시작될 때 데이터 모델을 초기화하려면 Global.asax.cs 파일에서 처리기를 업데이트 Application_Start 합니다.

참고

솔루션 탐색기 Global.asax 파일 또는 Global.asax.cs 파일을 선택하여 Global.asax.cs 파일을 편집할 수 있습니다.

  1. 노란색으로 강조 표시된 다음 코드를 Global.asax.cs 파일의 Application_Start 메서드에 추가합니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Optimization;
    using System.Web.Routing;
    using System.Web.Security;
    using System.Web.SessionState;
    using System.Data.Entity;
    using WingtipToys.Models;
    
    namespace WingtipToys
    {
        public class Global : HttpApplication
        {
            void Application_Start(object sender, EventArgs e)
            {
                // Code that runs on application startup
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                BundleConfig.RegisterBundles(BundleTable.Bundles);
    
                // Initialize the product database.
                Database.SetInitializer(new ProductDatabaseInitializer());
            }
        }
    }
    

참고

브라우저에서 이 자습서 시리즈를 볼 때 노란색으로 강조 표시된 코드를 보려면 브라우저에서 HTML5를 지원해야 합니다.

위의 코드에 표시된 것처럼 애플리케이션이 시작될 때 애플리케이션은 데이터에 처음 액세스할 때 실행되는 이니셜라이저를 지정합니다. 개체와 개체에 액세스 Database 하려면 두 개의 추가 네임스페이 ProductDatabaseInitializer 스가 필요합니다.

Web.Config 파일 수정

Entity Framework Code First는 데이터베이스가 시드 데이터로 채워질 때 기본 위치에 데이터베이스를 생성하지만 애플리케이션에 고유한 연결 정보를 추가하면 데이터베이스 위치를 제어할 수 있습니다. 프로젝트의 루트에 있는 애플리케이션의 Web.config 파일에서 연결 문자열을 사용하여 이 데이터베이스 연결을 지정합니다. 새 연결 문자열을 추가하여 데이터베이스의 위치(wingtiptoys.mdf)를 기본 위치가 아닌 애플리케이션의 데이터 디렉터리(App_Data)에 빌드하도록 지시할 수 있습니다. 이렇게 변경하면 이 자습서의 뒷부분에서 데이터베이스 파일을 찾아 검사할 수 있습니다.

  1. 솔루션 탐색기Web.config 파일을 찾아 엽니다.

  2. 다음과 같이 노란색으로 강조 표시된 연결 문자열을 <connectionStrings>Web.config 파일의 섹션에 추가합니다.

    <connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-WingtipToys-20131119102907.mdf;Initial Catalog=aspnet-WingtipToys-20131119102907;Integrated Security=True"
    providerName="System.Data.SqlClient" />
    <add name="WingtipToys"
    connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\wingtiptoys.mdf;Integrated Security=True"
    providerName="System.Data.SqlClient" />
    </connectionStrings>
    

애플리케이션이 처음으로 실행되면 연결 문자열에 지정된 위치에 데이터베이스를 빌드합니다. 그러나 애플리케이션을 실행하기 전에 먼저 빌드해 보겠습니다.

애플리케이션 빌드

웹 애플리케이션의 모든 클래스와 변경 내용이 작동하는지 확인하려면 애플리케이션을 빌드해야 합니다.

  1. 디버그 메뉴에서 WingtipToys 빌드를 선택합니다.
    출력 창이 표시되고 모두 잘 진행되면 성공 메시지가 표시됩니다.

    데이터 액세스 계층 만들기 - 출력 Windows

오류가 발생하면 위의 단계를 다시 검사. 출력 창의 정보는 문제가 있는 파일과 파일에서 변경이 필요한 위치를 나타냅니다. 이 정보를 통해 프로젝트에서 검토 및 수정해야 하는 위 단계의 일부를 확인할 수 있습니다.

요약

데이터 모델을 만든 시리즈의 이 자습서에서는 데이터베이스를 초기화하고 시드하는 데 사용할 코드를 추가했습니다. 또한 애플리케이션을 실행할 때 데이터 모델을 사용하도록 애플리케이션을 구성했습니다.

다음 자습서에서는 UI를 업데이트하고, 탐색을 추가하고, 데이터베이스에서 데이터를 검색합니다. 이렇게 하면 이 자습서에서 만든 엔터티 클래스에 따라 데이터베이스가 자동으로 만들어집니다.

추가 리소스

Entity Framework 개요
ADO.NET Entity Framework 초보자 가이드
Entity FrameworkCode First 관계 Fluent API를 사용한 코드 첫 번째 개발
Code First 데이터 주석
Entity Framework의 생산성 향상