다음을 통해 공유


ASP.NET MVC 애플리케이션에 대한 Entity Framework 데이터 모델 만들기(1/10)

작성자: Tom Dykstra

참고 항목

이 자습서 시리즈의 최신 버전은 Visual Studio 2013, Entity Framework 6 및 MVC 5에 사용할 수 있습니다.

Contoso University 샘플 웹 애플리케이션은 Entity Framework 5 및 Visual Studio 2012를 사용하여 ASP.NET MVC 4 애플리케이션을 만드는 방법을 보여 줍니다. 샘플 애플리케이션은 가상 Contoso University의 웹 사이트입니다. 학생 입학, 강좌 개설 및 강사 할당과 같은 기능이 있습니다. 이 자습서 시리즈에서는 Contoso University 샘플 애플리케이션을 빌드하는 방법을 설명합니다.

Code First

Entity Framework에서는 데이터베이스 우선, 모델 우선, 코드 우선세 가지 방법으로 데이터를 사용할 수 있습니다. 이 자습서는 Code First용입니다. 이러한 워크플로 간의 차이점과 시나리오에 가장 적합한 워크플로를 선택하는 방법에 대한 지침은 Entity Framework 개발 워크플로를 참조 하세요.

MVC

샘플 애플리케이션은 ASP.NET MVC를 기반으로 합니다. ASP.NET Web Forms 모델을 사용하려면 모델 바인딩 및 Web Forms 자습서 시리즈와 ASP.NET 데이터 액세스 콘텐츠 맵을 참조하세요.

소프트웨어 버전

자습서에 표시 또한 다음 작업
Windows 8 Windows 7
Visual Studio 2012 Visual Studio 2012 Express for Web. VS 2012 또는 VS 2012 Express for Web이 아직 없는 경우 Windows Azure SDK에서 자동으로 설치됩니다. Visual Studio 2013은 작동하지만 자습서는 테스트되지 않았으며 일부 메뉴 선택 및 대화 상자는 다릅니다. Windows Azure 배포에는 VS 2013 버전의 Windows Azure SDK 가 필요합니다.
.NET 4.5 표시된 대부분의 기능은 .NET 4에서 작동하지만 일부는 작동하지 않습니다. 예를 들어 EF의 열거형 지원에는 .NET 4.5가 필요합니다.
Entity Framework 5
Windows Azure SDK 2.1 Windows Azure 배포 단계를 건너뛰는 경우 SDK가 필요하지 않습니다. 새 버전의 SDK가 릴리스되면 링크에서 최신 버전을 설치합니다. 이 경우 일부 지침을 새 UI 및 기능에 맞게 조정해야 할 수 있습니다.

질문

자습서와 직접 관련이 없는 질문이 있는 경우 ASP.NET Entity Framework 포럼, Entity Framework 및 LINQ to Entities 포럼 또는 StackOverflow.com 게시할 수 있습니다.

승인

승인 및 VB에 대한 메모는 시리즈의 마지막 자습서를 참조하세요.

Contoso University 웹 애플리케이션

이 자습서에서 빌드하는 애플리케이션은 간단한 대학 웹 사이트입니다.

사용자는 학생, 강좌 및 강사 정보를 보고 업데이트할 수 있습니다. 다음은 만들 몇 가지 화면입니다.

Students_Index_page

샘플 Contoso University 웹 애플리케이션의 학생 검색 페이지 및 새 학생 만들기 페이지를 보여 주는 스크린샷

자습서가 Entity Framework를 사용하는 방법에 주로 초점을 맞출 수 있도록 이 사이트의 UI 스타일은 기본 제공 템플릿에서 생성된 내용에 가깝게 유지되었습니다.

필수 조건

이 자습서의 지침 및 스크린샷은 2013년 7월 현재 최신 업데이트 및 .NET용 Azure SDK가 설치된 Visual Studio 2012 또는 Visual Studio 2012 Express for Web을 사용한다고 가정합니다. 다음 링크를 사용하여 이 모든 것을 가져올 수 있습니다.

.NET용 Azure SDK(Visual Studio 2012)

Visual Studio를 설치한 경우 위의 링크에서 누락된 구성 요소를 설치합니다. Visual Studio가 없는 경우 링크는 Visual Studio 2012 Express for Web을 설치합니다. Visual Studio 2013을 사용할 수 있지만 필요한 절차와 화면 중 일부는 다릅니다.

MVC 웹 애플리케이션 만들기

Visual Studio를 열고 ASP.NET MVC 4 웹 애플리케이션 템플릿을 사용하여 "ContosoUniversity"라는 새 C# 프로젝트를 만듭니다. .NET Framework 4.5를 대상으로 지정해야 합니다(속성을 사용 enum 하며 .NET 4.5가 필요).

New_project_dialog_box

새 ASP.NET MVC 4 프로젝트 대화 상자에서 인터넷 애플리케이션 템플릿을 선택합니다.

Razor 보기 엔진을 선택한 상태로 두고 단위 테스트 프로젝트 만들기 확인란을 선택 취소된 상태로 둡니다.

확인을 클릭합니다.

Project_template_options

사이트 스타일 설정

몇 가지 간단한 변경 내용으로 사이트 메뉴, 레이아웃 및 홈 페이지를 설정합니다.

Views\Shared\_Layout.cshtml을 열고 파일 내용을 다음 코드로 바꿉니다. 변경 내용은 강조 표시되어 있습니다.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>@ViewBag.Title - Contoso University</title>
        <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
        <meta name="viewport" content="width=device-width" />
        @Styles.Render("~/Content/css")
        @Scripts.Render("~/bundles/modernizr")
    </head>
    <body>
        <header>
            <div class="content-wrapper">
                <div class="float-left">
                    <p class="site-title">@Html.ActionLink("Contoso University", "Index", "Home")</p>
                </div>
                <div class="float-right">
                    <section id="login">
                        @Html.Partial("_LoginPartial")
                    </section>
                    <nav>
                        <ul id="menu">
                            <li>@Html.ActionLink("Home", "Index", "Home")</li>
                            <li>@Html.ActionLink("About", "About", "Home")</li>
                            <li>@Html.ActionLink("Students", "Index", "Student")</li>
                            <li>@Html.ActionLink("Courses", "Index", "Course")</li>
                            <li>@Html.ActionLink("Instructors", "Index", "Instructor")</li>
                            <li>@Html.ActionLink("Departments", "Index", "Department")</li>
                        </ul>
                    </nav>
                </div>
            </div>
        </header>
        <div id="body">
            @RenderSection("featured", required: false)
            <section class="content-wrapper main-content clear-fix">
                @RenderBody()
            </section>
        </div>
        <footer>
            <div class="content-wrapper">
                <div class="float-left">
                    <p>&copy; @DateTime.Now.Year - Contoso University</p>
                </div>
            </div>
        </footer>

        @Scripts.Render("~/bundles/jquery")
        @RenderSection("scripts", required: false)
    </body>
</html>

이 코드로 다음이 변경됩니다.

  • "내 ASP.NET MVC 애플리케이션" 및 "여기 로고"의 템플릿 인스턴스를 "Contoso University"로 바꿉니다.
  • 자습서의 뒷부분에서 사용할 몇 가지 작업 링크를 추가합니다.

Views\Home\Index.cshtml에서 파일 내용을 다음 코드로 바꿔 ASP.NET 및 MVC에 대한 템플릿 단락을 제거합니다.

@{
    ViewBag.Title = "Home Page";
}
@section featured {
    <section class="featured">
        <div class="content-wrapper">
            <hgroup class="title">
                <h1>@ViewBag.Title.</h1>
                <h2>@ViewBag.Message</h2>
            </hgroup>
        </div>
    </section>
}

Controllers\HomeController.cs 다음 예제와 같이 Action 메서드의 Index 값을 ViewBag.Message "Contoso University 시작!"으로 변경합니다.

public ActionResult Index()
{
    ViewBag.Message = "Welcome to Contoso University";

    return View();
}

Ctrl+F5를 눌러 사이트를 실행합니다. 주 메뉴가 있는 홈페이지가 표시됩니다.

Contoso_University_home_page

데이터 모델 만들기

다음으로 Contoso University 애플리케이션에 대한 엔터티 클래스를 만듭니다. 다음 세 가지 엔터티로 시작합니다.

Class_diagram

StudentEnrollment 엔터티 간에 일대다 관계가 있으며 CourseEnrollment 엔터티 간에 일대다 관계가 있습니다. 즉, 학생은 개수에 관계 없이 강좌에 등록될 수 있으며 강좌는 등록된 학생이 여러 명일 수 있습니다.

다음 섹션에서 이러한 엔터티 각각에 대한 클래스를 만듭니다.

참고 항목

이러한 모든 엔터티 클래스 만들기를 완료하기 전에 프로젝트를 컴파일하려고 하면 컴파일러 오류가 발생합니다.

학생 엔터티

Student_entity

Models 폴더에서 Student.cs 만들고 기존 코드를 다음 코드로 바꿉다.

using System;
using System.Collections.Generic;

namespace ContosoUniversity.Models
{
    public class Student
    {
        public int StudentID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }
        
        public virtual ICollection<Enrollment> Enrollments { get; set; }
    }
}

StudentID 속성은 이 클래스에 해당하는 데이터베이스 테이블의 기본 키 열이 됩니다. 기본적으로 Entity Framework는 명명된 속성 또는 클래스 이름을 ID ID 기본 키로 해석합니다.

Enrollments 속성은 탐색 속성입니다. 탐색 속성은 이 엔터티와 관련된 다른 엔터티를 포함합니다. 이 경우 Enrollments 엔터티의 Student 속성은 해당 Student 엔터티와 Enrollment 관련된 모든 엔터티를 보유합니다. 즉, 데이터베이스의 지정된 Student 행에 두 개의 관련 Enrollment 행(해당 학생의 기본 키 값이 외래 키 열에 StudentID 포함된 행)이 있는 경우 해당 Student 엔터티의 Enrollments 탐색 속성에는 이러한 두 Enrollment 엔터티가 포함됩니다.

탐색 속성은 일반적으로 지연 로드와 virtual 같은 특정 Entity Framework 기능을 활용할 수 있도록 정의됩니다. 지연 로드는 나중에 에서 설명합니다.이 시리즈의 뒷부분에서 관련 데이터 읽기 자습서입니다.

탐색 속성이 여러 엔터티를 포함할 수 있는 경우(다대다 또는 일대다 관계로), 해당 형식은 ICollection와 같이 항목이 추가, 삭제 및 업데이트될 수 있는 목록이어야 합니다.

등록 엔터티

Enrollment_entity

Models 폴더에서Enrollment.cs를 만들고 기존 코드를 다음 코드로 바꿉니다.

namespace ContosoUniversity.Models
{
    public enum Grade
    {
        A, B, C, D, F
    }

    public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        public Grade? Grade { get; set; }
        
        public virtual Course Course { get; set; }
        public virtual Student Student { get; set; }
    }
}

Grade 속성은 열거형입니다. Grade 형식 선언 뒤에 있는 물음표는 Grade 속성이 nullable이라는 것을 나타냅니다. null인 성적은 0등급과 다릅니다. null은 성적을 알 수 없거나 아직 할당되지 않았음을 의미합니다.

StudentID 속성은 외래 키로, 해당 탐색 속성은 Student입니다. Enrollment 엔터티는 하나의 Student 엔터티와 연결되어 있으므로 속성은 단일 Student 엔터티만 포함할 수 있습니다(이전에 살펴본 여러 Enrollment 엔터티를 포함할 수 있는 Student.Enrollments 탐색 속성과 달리).

CourseID 속성은 외래 키로, 해당 탐색 속성은 Course입니다. Enrollment 엔터티는 하나의 Course 엔터티와 연결됩니다.

Course 엔터티

Course_entity

Models 폴더에서 기존 코드를 다음 코드로 바꿔서 Course.cs 만듭니다.

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CourseID { get; set; }
        public string Title { get; set; }
        public int Credits { get; set; }
        
        public virtual ICollection<Enrollment> Enrollments { get; set; }
    }
}

Enrollments 속성은 탐색 속성입니다. Course 엔터티는 Enrollment 엔터티의 개수와 관련이 있을 수 있습니다.

[DatabaseGenerated(DatabaseGeneratedOption)에 대해 자세히 살펴보겠습니다. 없음)] 다음 자습서의 특성입니다. 기본적으로 이 특성을 통해 생성하는 데이터베이스를 갖는 대신 강좌에 대한 기본 키를 입력할 수 있습니다.

데이터베이스 컨텍스트 만들기

지정된 데이터 모델에 대한 Entity Framework 기능을 조정하는 기본 클래스는 데이터베이스 컨텍스트 클래스입니다. System.Data.Entity.DbContext 클래스에서 파생하여 이 클래스를 만듭니다 . 코드에서 데이터 모델에 포함되는 엔터티를 지정합니다. 특정 Entity Framework 동작을 사용자 지정할 수도 있습니다. 이 프로젝트에서 클래스 이름은 SchoolContext로 지정됩니다.

DAL(데이터 액세스 계층용)이라는 폴더를 만듭니다. 해당 폴더에서 SchoolContext.cs클래스 파일을 만들고 기존 코드를 다음 코드로 바꿉다.

using ContosoUniversity.Models;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;

namespace ContosoUniversity.DAL
{
    public class SchoolContext : DbContext
    {
        public DbSet<Student> Students { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Course> Courses { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        }
    }
}

이 코드는 각 엔터티 집합에 대한 DbSet 속성을 만듭니다. Entity Framework 용어 에서 엔터티 집합 은 일반적으로 데이터베이스 테이블에 해당하며 엔터티는 테이블의 행에 해당합니다.

OnModelCreating 메서드의 문은 modelBuilder.Conventions.Remove 테이블 이름이 복수화되지 않도록 방지합니다. 이 작업을 수행하지 않은 경우 생성된 테이블의 이름은 StudentsCoursesEnrollments. 대신 테이블 이름은 Student, CourseEnrollment. 개발자는 테이블 이름을 복수화할지 여부에 대해 동의하지 않습니다. 이 자습서에서는 단수 형식을 사용하지만 중요한 점은 이 코드 줄을 포함하거나 생략하여 원하는 양식을 선택할 수 있다는 것입니다.

SQL Server Express LocalDB

LocalDB는 요청 시 시작하여 사용자 모드에서 실행되는 SQL Server Express 데이터베이스 엔진 경량 버전입니다. LocalDB는 데이터베이스를 .mdf 파일로 사용할 수 있도록 하는 SQL Server Express의 특수 실행 모드에서 실행됩니다. 일반적으로 LocalDB 데이터베이스 파일은 웹 프로젝트의 App_Data 폴더에 보관됩니다. 또한 SQL Server Express의 사용자 인스턴스 기능을 사용하면 .mdf 파일로 작업할 수 있지만 사용자 인스턴스 기능은 더 이상 사용되지 않으므로 .mdf 파일 작업에 LocalDB를 사용하는 것이 좋습니다.

일반적으로 SQL Server Express는 프로덕션 웹 애플리케이션에 사용되지 않습니다. 특히 LocalDB는 IIS로 작동하도록 설계되지 않았기 때문에 웹 애플리케이션에서 프로덕션에 사용하지 않는 것이 좋습니다.

Visual Studio 2012 이상 버전에서는 LocalDB가 기본적으로 Visual Studio와 함께 설치됩니다. Visual Studio 2010 및 이전 버전에서는 Visual Studio와 함께 SQL Server Express(LocalDB 제외)가 기본적으로 설치됩니다. Visual Studio 2010을 사용하는 경우 수동으로 설치해야 합니다.

이 자습서에서는 데이터베이스를 App_Data 폴더에 .mdf 파일로 저장할 수 있도록 LocalDB로 작업합니다. 다음 예제와 같이 루트 Web.config 파일을 열고 컬렉션에 connectionStrings 새 연결 문자열 추가합니다. (다음을 업데이트해야 합니다.루트 프로젝트 폴더의 Web.config 파일입니다. 업데이트할 필요가 없는 Views 하위 폴더에 Web.config 파일도 있습니다.)

<add name="SchoolContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=ContosoUniversity;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\ContosoUniversity.mdf" providerName="System.Data.SqlClient" />

기본적으로 Entity Framework는 클래스와 동일한 DbContext 이름의 연결 문자열 찾습니다(SchoolContext이 프로젝트의 경우). 추가한 연결 문자열 App_Data 폴더에 있는 ContosoUniversity.mdf 라는 LocalDB 데이터베이스를 지정합니다. 자세한 내용은 ASP.NET 웹 애플리케이션에 대한 SQL Server 연결 문자열을 참조 하세요.

실제로 연결 문자열 지정할 필요가 없습니다. 연결 문자열 제공하지 않으면 Entity Framework에서 만들 수 있지만 데이터베이스가 앱의 App_data 폴더에 없을 수 있습니다. 데이터베이스를 만들 위치에 대한 자세한 내용은 새 데이터베이스에 대한 Code First를 참조하세요.

컬렉션에는 connectionStrings 멤버 자격 데이터베이스에 사용되는 명명 DefaultConnection 된 연결 문자열 있습니다. 이 자습서에서는 멤버 자격 데이터베이스를 사용하지 않습니다. 두 연결 문자열 간의 유일한 차이점은 데이터베이스 이름과 이름 특성 값입니다.

Code First 마이그레이션 설정 및 실행

애플리케이션 개발을 처음 시작하면 데이터 모델이 자주 변경되고 모델이 변경되면 데이터베이스와의 동기화가 중단됩니다. 데이터 모델을 변경할 때마다 데이터베이스를 자동으로 삭제하고 다시 만들도록 Entity Framework를 구성할 수 있습니다. 테스트 데이터가 쉽게 다시 생성되기 때문에 개발 초기에는 문제가 되지 않지만 프로덕션 환경에 배포한 후에는 일반적으로 데이터베이스를 삭제하지 않고 데이터베이스 스키마를 업데이트하려고 합니다. 마이그레이션 기능을 사용하면 Code First에서 데이터베이스를 삭제하고 다시 만들지 않고도 업데이트할 수 있습니다. 새 프로젝트의 개발 주기 초기에 DropCreateDatabaseIfModelChanges를 사용하여 모델이 변경될 때마다 데이터베이스를 삭제, 다시 만들고 다시 시드할 수 있습니다. 애플리케이션을 배포할 준비가 되면 마이그레이션 접근 방식으로 변환할 수 있습니다. 이 자습서에서는 마이그레이션만 사용합니다. 자세한 내용은 Code First 마이그레이션마이그레이션 스크린캐스트 시리즈를 참조하세요.

Code First 마이그레이션 사용

  1. 도구 메뉴에서 NuGet 패키지 관리자 클릭한 다음 콘솔을 패키지 관리자.

    Selecting_Package_Manager_Console

  2. 프롬프트에서 PM> 다음 명령을 입력합니다.

    enable-migrations -contexttypename SchoolContext
    

    enable-migrations 명령

    이 명령은 ContosoUniversity 프로젝트에 Migrations 폴더를 만들고 마이그레이션을 구성하기 위해 편집할 수 있는 Configuration.cs 파일을 해당 폴더에 넣습니다.

    마이그레이션 폴더

    클래스에는 Configuration 데이터베이스를 Seed 만들 때와 데이터 모델 변경 후 업데이트할 때마다 호출되는 메서드가 포함됩니다.

    internal sealed class Configuration : DbMigrationsConfiguration<ContosoUniversity.Models.SchoolContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }
    
        protected override void Seed(ContosoUniversity.Models.SchoolContext context)
        {
            //  This method will be called after migrating to the latest version.
    
            //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
            //  to avoid creating duplicate seed data. E.g.
            //
            //    context.People.AddOrUpdate(
            //      p => p.FullName,
            //      new Person { FullName = "Andrew Peters" },
            //      new Person { FullName = "Brice Lambson" },
            //      new Person { FullName = "Rowan Miller" }
            //    );
            //
        }
    }
    

    Seed 메서드의 목적은 Code First에서 테스트 데이터를 만들거나 업데이트한 후 데이터베이스에 테스트 데이터를 삽입할 수 있도록 하는 것입니다.

Seed 메서드 설정

Seed 메서드는 Code First 마이그레이션 데이터베이스를 만들고 데이터베이스를 최신 마이그레이션으로 업데이트할 때마다 실행됩니다. Seed 메서드의 목적은 애플리케이션이 데이터베이스에 처음으로 액세스하기 전에 테이블에 데이터를 삽입할 수 있도록 하는 것입니다.

이전 버전의 Code First에서는 마이그레이션이 릴리스되기 전에 개발 중에 모든 모델이 변경될 때마다 데이터베이스를 완전히 삭제하고 처음부터 다시 만들어야 했기 때문에 메서드에서 테스트 데이터를 삽입하는 것이 일반적 Seed 이었습니다. Code First 마이그레이션 경우 데이터베이스 변경 후 테스트 데이터가 유지되므로 Seed 메서드에 테스트 데이터를 포함할 필요가 없습니다. 실제로 마이그레이션을 사용하여 프로덕션에 데이터베이스를 배포하는 경우 메서드가 테스트 데이터를 삽입하지 않도록 Seed 합니다. 이 메서드는 프로덕션 환경에서 실행되기 때문 Seed 입니다. 이 경우 프로덕션에 Seed 삽입하려는 데이터만 데이터베이스에 삽입하도록 합니다. 예를 들어 프로덕션 환경에서 애플리케이션을 사용할 수 있게 되면 데이터베이스가 Department 테이블에 실제 부서 이름을 포함하도록 할 수 있습니다.

이 자습서에서는 배포에 마이그레이션을 사용하지만 Seed 많은 데이터를 수동으로 삽입하지 않고도 애플리케이션 기능이 작동하는 방식을 더 쉽게 확인할 수 있도록 메서드가 테스트 데이터를 삽입합니다.

  1. Configuration.cs 파일의 내용을 테스트 데이터를 새 데이터베이스에 로드하는 다음 코드로 바꿉니다.

    namespace ContosoUniversity.Migrations
    {
       using System;
       using System.Collections.Generic;
       using System.Data.Entity.Migrations;
       using System.Linq;
       using ContosoUniversity.Models;
    
       internal sealed class Configuration : DbMigrationsConfiguration<ContosoUniversity.DAL.SchoolContext>
       {
          public Configuration()
          {
             AutomaticMigrationsEnabled = false;
          }
    
          protected override void Seed(ContosoUniversity.DAL.SchoolContext context)
          {
             var students = new List<Student>
                {
                    new Student { FirstMidName = "Carson",   LastName = "Alexander", 
                        EnrollmentDate = DateTime.Parse("2010-09-01") },
                    new Student { FirstMidName = "Meredith", LastName = "Alonso",    
                        EnrollmentDate = DateTime.Parse("2012-09-01") },
                    new Student { FirstMidName = "Arturo",   LastName = "Anand",     
                        EnrollmentDate = DateTime.Parse("2013-09-01") },
                    new Student { FirstMidName = "Gytis",    LastName = "Barzdukas", 
                        EnrollmentDate = DateTime.Parse("2012-09-01") },
                    new Student { FirstMidName = "Yan",      LastName = "Li",        
                        EnrollmentDate = DateTime.Parse("2012-09-01") },
                    new Student { FirstMidName = "Peggy",    LastName = "Justice",   
                        EnrollmentDate = DateTime.Parse("2011-09-01") },
                    new Student { FirstMidName = "Laura",    LastName = "Norman",    
                        EnrollmentDate = DateTime.Parse("2013-09-01") },
                    new Student { FirstMidName = "Nino",     LastName = "Olivetto",  
                        EnrollmentDate = DateTime.Parse("2005-08-11") }
                };
             students.ForEach(s => context.Students.AddOrUpdate(p => p.LastName, s));
             context.SaveChanges();
    
             var courses = new List<Course>
                {
                    new Course {CourseID = 1050, Title = "Chemistry",      Credits = 3, },
                    new Course {CourseID = 4022, Title = "Microeconomics", Credits = 3, },
                    new Course {CourseID = 4041, Title = "Macroeconomics", Credits = 3, },
                    new Course {CourseID = 1045, Title = "Calculus",       Credits = 4, },
                    new Course {CourseID = 3141, Title = "Trigonometry",   Credits = 4, },
                    new Course {CourseID = 2021, Title = "Composition",    Credits = 3, },
                    new Course {CourseID = 2042, Title = "Literature",     Credits = 4, }
                };
             courses.ForEach(s => context.Courses.AddOrUpdate(p => p.Title, s));
             context.SaveChanges();
    
             var enrollments = new List<Enrollment>
                {
                    new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").StudentID, 
                        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID, 
                        Grade = Grade.A 
                    },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").StudentID,
                        CourseID = courses.Single(c => c.Title == "Microeconomics" ).CourseID, 
                        Grade = Grade.C 
                     },                            
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").StudentID,
                        CourseID = courses.Single(c => c.Title == "Macroeconomics" ).CourseID, 
                        Grade = Grade.B
                     },
                     new Enrollment { 
                         StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
                        CourseID = courses.Single(c => c.Title == "Calculus" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment { 
                         StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
                        CourseID = courses.Single(c => c.Title == "Trigonometry" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment {
                        StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
                        CourseID = courses.Single(c => c.Title == "Composition" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Anand").StudentID,
                        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Anand").StudentID,
                        CourseID = courses.Single(c => c.Title == "Microeconomics").CourseID,
                        Grade = Grade.B         
                     },
                    new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Barzdukas").StudentID,
                        CourseID = courses.Single(c => c.Title == "Chemistry").CourseID,
                        Grade = Grade.B         
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Li").StudentID,
                        CourseID = courses.Single(c => c.Title == "Composition").CourseID,
                        Grade = Grade.B         
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Justice").StudentID,
                        CourseID = courses.Single(c => c.Title == "Literature").CourseID,
                        Grade = Grade.B         
                     }
                };
    
             foreach (Enrollment e in enrollments)
             {
                var enrollmentInDataBase = context.Enrollments.Where(
                    s =>
                         s.Student.StudentID == e.StudentID &&
                         s.Course.CourseID == e.CourseID).SingleOrDefault();
                if (enrollmentInDataBase == null)
                {
                   context.Enrollments.Add(e);
                }
             }
             context.SaveChanges();
          }
       }
    }
    

    Seed 메서드는 데이터베이스 컨텍스트 개체를 입력 매개 변수로 사용하고 메서드의 코드는 해당 개체를 사용하여 데이터베이스에 새 엔터티를 추가합니다. 각 엔터티 형식에 대해 코드는 새 엔터티 컬렉션을 만들고 적절한 DbSet 속성에 추가한 다음 변경 내용을 데이터베이스에 저장합니다. 여기에서와 같이 각 엔터티 그룹 다음에 SaveChanges 메서드를 호출할 필요는 없지만, 이렇게 하면 코드가 데이터베이스에 쓰는 동안 예외가 발생하는 경우 문제의 원인을 찾을 수 있습니다.

    데이터를 삽입하는 일부 문은 AddOrUpdate 메서드를 사용하여 "upsert" 작업을 수행합니다. 메서드는 Seed 모든 마이그레이션에서 실행되므로 추가하려는 행이 데이터베이스를 만드는 첫 번째 마이그레이션 후에 이미 있기 때문에 데이터를 삽입할 수 없습니다. "upsert" 작업은 이미 존재하는 행을 삽입하려고 할 때 발생하는 오류를 방지하지만 애플리케이션을 테스트하는 동안 수행한 데이터의 변경 내용을 재정의합니다 . 일부 테이블의 테스트 데이터를 사용하면 이러한 문제가 발생하지 않도록 할 수 있습니다. 경우에 따라 테스트하는 동안 데이터를 변경할 때 데이터베이스 업데이트 후에도 변경 내용을 유지하려고 합니다. 이 경우 조건부 삽입 작업을 수행하려고 합니다. 행이 아직 없는 경우에만 행을 삽입합니다. Seed 메서드는 두 가지 방법을 모두 사용합니다.

    AddOrUpdate 메서드에 전달된 첫 번째 매개 변수는 행이 이미 있는지 확인하는 데 사용할 속성을 지정합니다. 제공 중인 시험 학생 데이터의 경우 목록의 LastName 각 성은 고유하므로 이 용도로 속성을 사용할 수 있습니다.

    context.Students.AddOrUpdate(p => p.LastName, s)
    

    이 코드는 성이 고유하다고 가정합니다. 성이 중복된 학생을 수동으로 추가하는 경우 다음에 마이그레이션을 수행할 때 다음 예외가 발생합니다.

    시퀀스에 둘 이상의 요소가 포함됩니다.

    이 방법에 대한 AddOrUpdate 자세한 내용은 Julie Lerman의 블로그에서 EF 4.3 AddOrUpdate 메서드 를 사용하여 주의하세요.

    엔터티를 추가하는 Enrollment 코드는 메서드를 AddOrUpdate 사용하지 않습니다. 엔터티가 이미 있는지 확인하고 엔터티가 없는 경우 삽입합니다. 이 방법은 마이그레이션을 실행할 때 등록 등급에 대한 변경 내용을 유지합니다. 코드는 목록의 각 멤버를 Enrollment반복하고 데이터베이스에서 등록을 찾을 수 없는 경우 데이터베이스에 등록을 추가합니다. 데이터베이스를 처음 업데이트하면 데이터베이스가 비어 있으므로 각 등록이 추가됩니다.

    foreach (Enrollment e in enrollments)
    {
        var enrollmentInDataBase = context.Enrollments.Where(
            s => s.Student.StudentID == e.Student.StudentID &&
                 s.Course.CourseID == e.Course.CourseID).SingleOrDefault();
        if (enrollmentInDataBase == null)
        {
            context.Enrollments.Add(e);
        }
    }
    

    메서드를 디버그 Seed 하는 방법 및 "Alexander Carson"이라는 두 학생과 같은 중복 데이터를 처리하는 방법에 대한 자세한 내용은 Rick Anderson의 블로그에서 EF(Entity Framework) DB 시드 및 디버깅을 참조하세요.

  2. 프로젝트를 빌드합니다.

첫 번째 마이그레이션 만들기 및 실행

  1. 패키지 관리자 콘솔 창에서 다음 명령을 입력합니다.

    add-migration InitialCreate
    update-database
    

    패키지 관리자 콘솔 창을 보여 주는 스크린샷 이 명령은 하이픈 마이그레이션 밑줄을 추가합니다. 초기 만들기 및 업데이트 하이픈 데이터베이스가 강조 표시됩니다.

    add-migration 명령은 데이터베이스를 만드는 코드를 포함하는 [DateStamp]_InitialCreate.cs 파일을 Migrations 폴더에 추가합니다. 첫 번째 매개 변수InitialCreate) (파일 이름에 사용되며 원하는 대로 될 수 있습니다. 일반적으로 마이그레이션에서 수행되는 작업을 요약하는 단어 또는 구를 선택합니다. 예를 들어 이후 마이그레이션의 이름을 “AddDepartmentTable”로 지정할 수도 있습니다.

    초기 마이그레이션을 사용하는 마이그레이션 폴더

    클래스의 InitialCreate 메서드는 Up 데이터 모델 엔터티 집합에 해당하는 데이터베이스 테이블을 만들고 메서드는 Down 이를 삭제합니다. 마이그레이션에서는 마이그레이션을 위한 데이터 모델 변경을 구현하기 위해 Up 메서드를 호출합니다. 업데이트를 롤백하는 명령을 입력하면 마이그레이션에서 Down 메서드를 호출합니다. 다음 코드는 파일의 InitialCreate 내용을 보여 줍니다.

    namespace ContosoUniversity.Migrations
    {
        using System;
        using System.Data.Entity.Migrations;
        
        public partial class InitialCreate : DbMigration
        {
            public override void Up()
            {
                CreateTable(
                    "dbo.Student",
                    c => new
                        {
                            StudentID = c.Int(nullable: false, identity: true),
                            LastName = c.String(),
                            FirstMidName = c.String(),
                            EnrollmentDate = c.DateTime(nullable: false),
                        })
                    .PrimaryKey(t => t.StudentID);
                
                CreateTable(
                    "dbo.Enrollment",
                    c => new
                        {
                            EnrollmentID = c.Int(nullable: false, identity: true),
                            CourseID = c.Int(nullable: false),
                            StudentID = c.Int(nullable: false),
                            Grade = c.Int(),
                        })
                    .PrimaryKey(t => t.EnrollmentID)
                    .ForeignKey("dbo.Course", t => t.CourseID, cascadeDelete: true)
                    .ForeignKey("dbo.Student", t => t.StudentID, cascadeDelete: true)
                    .Index(t => t.CourseID)
                    .Index(t => t.StudentID);
                
                CreateTable(
                    "dbo.Course",
                    c => new
                        {
                            CourseID = c.Int(nullable: false),
                            Title = c.String(),
                            Credits = c.Int(nullable: false),
                        })
                    .PrimaryKey(t => t.CourseID);
                
            }
            
            public override void Down()
            {
                DropIndex("dbo.Enrollment", new[] { "StudentID" });
                DropIndex("dbo.Enrollment", new[] { "CourseID" });
                DropForeignKey("dbo.Enrollment", "StudentID", "dbo.Student");
                DropForeignKey("dbo.Enrollment", "CourseID", "dbo.Course");
                DropTable("dbo.Course");
                DropTable("dbo.Enrollment");
                DropTable("dbo.Student");
            }
        }
    }
    

    update-database 명령은 메서드를 Up 실행하여 데이터베이스를 만든 다음 데이터베이스를 Seed 채우는 메서드를 실행합니다.

이제 데이터 모델에 대한 SQL Server 데이터베이스가 만들어졌습니다. 데이터베이스 이름은 ContosoUniversity이고 .mdf 파일은 연결 문자열 지정한 내용이므로 프로젝트의 App_Data 폴더에 있습니다.

서버 탐색기 또는 SSOX(SQL Server 개체 탐색기)를 사용하여 Visual Studio에서 데이터베이스를 볼 수 있습니다. 이 자습서에서는 서버 탐색기를 사용합니다. Visual Studio Express 2012 for Web에서 서버 탐색기를 데이터베이스 탐색기라고 합니다.

  1. 보기 메뉴에서 서버 탐색기를 클릭합니다.

  2. 연결 추가 아이콘을 클릭합니다.

    데이터베이스 탐색기 창을 보여 주는 스크린샷 연결 추가 아이콘이 강조 표시됩니다.

  3. 데이터 원본 선택 대화 상자가 표시되면 Microsoft SQL Server를 클릭한 다음 계속을 클릭합니다.

    데이터 원본 선택 대화 상자를 보여 주는 스크린샷 Microsoft S QL 서버 데이터 원본이 선택됩니다.

  4. 연결 추가 대화 상자에서 서버 이름에 (localdb)\v11.0입력합니다. 데이터베이스 이름 선택 또는 입력에서 ContosoUniversity를 선택합니다.

    연결 추가 대화 상자를 보여 주는 스크린샷. 샘플 서버 이름 및 Contoso University 데이터베이스가 강조 표시됩니다.

  5. 확인을 클릭합니다.

  6. SchoolContext를 확장 다음 테이블을 확장 합니다.

    서버 탐색기 페이지를 보여 주는 스크린샷 학교 컨텍스트 및 테이블 탭이 확장됩니다.

  7. 학생 테이블을 마우스 오른쪽 단추로 클릭하고 테이블 데이터 표시를 클릭하여 생성된 열과 테이블에 삽입된 행을 확인합니다.

    학생 테이블

학생 컨트롤러 및 뷰 만들기

다음 단계는 이러한 테이블 중 하나에서 작동할 수 있는 ASP.NET MVC 컨트롤러 및 뷰를 애플리케이션에 만드는 것입니다.

  1. 컨트롤러를 Student 만들려면 솔루션 탐색기 Controllers 폴더를 마우스 오른쪽 단추로 클릭하고 추가를 선택한 다음 컨트롤러를 클릭합니다. 컨트롤러 추가 대화 상자에서 다음을 선택하고 추가를 클릭합니다.

    • 컨트롤러 이름: StudentController.

    • 템플릿: Entity Framework를 사용하여 읽기/쓰기 작업 및 뷰가 있는 MVC 컨트롤러입니다.

    • 모델 클래스: Student(ContosoUniversity.Models). 드롭다운 목록에 이 옵션이 표시되지 않으면 프로젝트를 빌드하고 다시 시도하세요.

    • 데이터 컨텍스트 클래스: SchoolContext(ContosoUniversity.Models).

    • 보기: Razor(CSHTML). (기본값)

      Add_Controller_dialog_box_for_Student_controller

  2. Visual Studio에서 Controllers\StudentController.cs 파일을 엽니다. 데이터베이스 컨텍스트 개체를 인스턴스화하는 클래스 변수가 생성된 것을 볼 수 있습니다.

    private SchoolContext db = new SchoolContext();
    

    작업 메서드는 Index 데이터베이스 컨텍스트 인스턴스의 속성을 읽 Students 어 학생 엔터티 집합에서 학생 목록을 가져옵니다.

    public ViewResult Index()
    {
        return View(db.Students.ToList());
    }
    

    Student\Index.cshtml 보기는 테이블에 다음 목록을 표시합니다.

    <table>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.LastName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.FirstMidName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.EnrollmentDate)
            </th>
            <th></th>
        </tr>
    
    @foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.LastName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.FirstMidName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.EnrollmentDate)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { id=item.StudentID }) |
                @Html.ActionLink("Details", "Details", new { id=item.StudentID }) |
                @Html.ActionLink("Delete", "Delete", new { id=item.StudentID })
            </td>
        </tr>
    }
    
  3. Ctrl+F5를 눌러 프로젝트를 실행합니다.

    학생 탭을 클릭하여 메서드가 Seed 삽입한 테스트 데이터를 확인합니다.

    학생 인덱스 페이지

규칙

Entity Framework가 완전한 데이터베이스를 만들 수 있도록 하기 위해 작성해야 하는 코드의 양은 규칙 또는 Entity Framework에서 만드는 가정 때문에 최소화됩니다. 그들 중 일부는 이미 언급되었습니다 :

  • 복수 형식의 엔터티 클래스 이름은 테이블 이름으로 사용됩니다.
  • 엔터티 속성 이름은 열 이름에 사용됩니다.
  • 명명되거나 클래스 ID 이름 ID 인 엔터티 속성은 기본 키 속성으로 인식됩니다.

규칙을 재정의할 수 있음을 확인했습니다(예: 테이블 이름을 복수화해서는 안 됨). 이 시리즈의 뒷부분에 있는 더 복잡한 데이터 모델 만들기 자습서에서 규칙 및 이를 재정의하는 방법에 대해 자세히 알아봅니다. 자세한 내용은 Code First 규칙을 참조 하세요.

요약

이제 Entity Framework 및 SQL Server Express를 사용하여 데이터를 저장하고 표시하는 간단한 애플리케이션을 만들었습니다. 다음 자습서에서는 기본 CRUD(만들기, 읽기, 업데이트, 삭제) 작업을 수행하는 방법을 알아봅니다. 이 페이지의 맨 아래에 피드백을 남길 수 있습니다. 자습서의 이 부분을 어떻게 좋아했는지, 어떻게 개선할 수 있는지 알려주세요.

다른 Entity Framework 리소스에 대한 링크는 ASP.NET 데이터 액세스 콘텐츠 맵에서 찾을 수 있습니다.