다음을 통해 공유


자습서: ASP.NET MVC 앱에서 EF 마이그레이션을 사용하고 Azure에 배포

지금까지 Contoso University 샘플 웹 애플리케이션은 개발 컴퓨터의 IIS Express에서 로컬로 실행되었습니다. 다른 사용자가 인터넷을 통해 사용할 수 있는 실제 애플리케이션을 만들려면 웹 호스팅 공급자에 배포해야 합니다. 이 자습서에서는 Code First 마이그레이션을 사용하도록 설정하고 Azure에서 클라우드에 애플리케이션을 배포합니다.

  • Code First 마이그레이션 사용하도록 설정합니다. 마이그레이션 기능을 사용하면 데이터베이스를 삭제하고 다시 만들지 않고도 데이터베이스 스키마를 업데이트하여 데이터 모델을 변경하고 프로덕션 환경에 변경 내용을 배포할 수 있습니다.
  • Azure에 배포. 이 단계는 선택 사항입니다. 프로젝트를 배포하지 않고도 나머지 자습서를 계속 진행할 수 있습니다.

배포를 위해 소스 제어와 함께 연속 통합 프로세스를 사용하는 것이 좋지만 이 자습서에서는 해당 항목을 다루지 않습니다. 자세한 내용은 Azure를 사용하여 Real-World Cloud Apps 빌드의 소스 제어연속 통합 장을 참조하세요.

이 자습서에서는 다음을 수행합니다.

  • Code First 마이그레이션 사용
  • Azure에서 앱 배포(선택 사항)

필수 조건

Code First 마이그레이션 사용

새 애플리케이션을 개발하는 경우 데이터 모델은 자주 변경되며 모델이 변경될 때마다 데이터베이스와 동기화를 가져옵니다. 데이터 모델을 변경할 때마다 데이터베이스를 자동으로 삭제하고 다시 만들도록 Entity Framework를 구성했습니다. 엔터티 클래스를 추가, 제거 또는 변경하거나 클래스를 변경할 DbContext 때 다음에 애플리케이션을 실행하면 기존 데이터베이스가 자동으로 삭제되고 모델과 일치하는 새 데이터베이스가 만들어지고 테스트 데이터로 시드됩니다.

데이터베이스를 데이터 모델과 동기화된 상태로 유지하는 이 메서드는 애플리케이션을 프로덕션 환경에 배포할 때까지 잘 작동합니다. 애플리케이션이 프로덕션 환경에서 실행되는 경우 일반적으로 유지하려는 데이터를 저장하며, 새 열 추가와 같은 변경 작업을 수행할 때마다 모든 것을 잃지 않으려는 것입니다. Code First 마이그레이션 기능은 데이터베이스를 삭제하고 다시 만드는 대신 Code First에서 데이터베이스 스키마를 업데이트할 수 있도록 하여 이 문제를 해결합니다. 이 자습서에서는 애플리케이션을 배포하고 이를 준비하기 위해 마이그레이션을 사용하도록 설정합니다.

  1. 애플리케이션 Web.config 파일에 추가한 요소를 주석 처리하거나 삭제하여 contexts 이전에 설정한 이니셜라이저를 사용하지 않도록 설정합니다.

    <entityFramework>
      <!--<contexts>
        <context type="ContosoUniversity.DAL.SchoolContext, ContosoUniversity">
          <databaseInitializer type="ContosoUniversity.DAL.SchoolInitializer, ContosoUniversity" />
        </context>
      </contexts>-->
      <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
        <parameters>
          <parameter value="v11.0" />
        </parameters>
      </defaultConnectionFactory>
      <providers>
        <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
      </providers>
    </entityFramework>
    
  2. 또한 Application Web.config 파일에서 연결 문자열 데이터베이스의 이름을 ContosoUniversity2로 변경합니다.

    <connectionStrings>
      <add name="SchoolContext" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=ContosoUniversity2;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
    </connectionStrings>
    

    이 변경은 첫 번째 마이그레이션에서 새 데이터베이스를 만들도록 프로젝트를 설정합니다. 이 작업은 필수는 아니지만 나중에 좋은 이유를 확인할 수 있습니다.

  3. 도구 메뉴에서 NuGet 패키지 관리자>패키지 관리자 콘솔을 선택합니다.

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

    enable-migrations
    add-migration InitialCreate
    

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

    (데이터베이스 이름을 변경하도록 지시하는 위의 단계를 놓친 경우 마이그레이션은 기존 데이터베이스를 찾고 자동으로 명령을 수행 add-migration 합니다. 괜찮습니다. 데이터베이스를 배포하기 전에 마이그레이션 코드 테스트를 실행하지 않음을 의미합니다. 나중에 명령을 실행할 때 데이터베이스가 update-database 이미 있으므로 아무 일도 발생하지 않습니다.)

    ContosoUniversity\Migrations\Configuration.cs 파일을 엽니다. 앞에서 본 이니셜라이저 클래스와 마찬가지로 클래스에는 Configuration 메서드가 Seed 포함됩니다.

    internal sealed class Configuration : DbMigrationsConfiguration<ContosoUniversity.DAL.SchoolContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }
    
        protected override void Seed(ContosoUniversity.DAL.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 메서드에 테스트 데이터를 포함할 필요가 없습니다. 실제로 마이그레이션을 사용하여 프로덕션에 데이터베이스를 배포하는 경우 메서드가 테스트 데이터를 삽입하지 않도록 Seed 합니다. 이 메서드는 프로덕션 환경에서 실행되기 때문 Seed 입니다. 이 경우 메서드가 프로덕션에 Seed 필요한 데이터만 데이터베이스에 삽입하려고 합니다. 예를 들어 프로덕션 환경에서 애플리케이션을 사용할 수 있게 되면 데이터베이스가 Department 테이블에 실제 부서 이름을 포함하도록 할 수 있습니다.

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

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

    namespace ContosoUniversity.Migrations
    {
        using ContosoUniversity.Models;
        using System;
        using System.Collections.Generic;
        using System.Data.Entity;
        using System.Data.Entity.Migrations;
        using System.Linq;
    
        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").ID, 
                        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID, 
                        Grade = Grade.A 
                    },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").ID,
                        CourseID = courses.Single(c => c.Title == "Microeconomics" ).CourseID, 
                        Grade = Grade.C 
                     },                            
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").ID,
                        CourseID = courses.Single(c => c.Title == "Macroeconomics" ).CourseID, 
                        Grade = Grade.B
                     },
                     new Enrollment { 
                         StudentID = students.Single(s => s.LastName == "Alonso").ID,
                        CourseID = courses.Single(c => c.Title == "Calculus" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment { 
                         StudentID = students.Single(s => s.LastName == "Alonso").ID,
                        CourseID = courses.Single(c => c.Title == "Trigonometry" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment {
                        StudentID = students.Single(s => s.LastName == "Alonso").ID,
                        CourseID = courses.Single(c => c.Title == "Composition" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Anand").ID,
                        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Anand").ID,
                        CourseID = courses.Single(c => c.Title == "Microeconomics").CourseID,
                        Grade = Grade.B         
                     },
                    new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Barzdukas").ID,
                        CourseID = courses.Single(c => c.Title == "Chemistry").CourseID,
                        Grade = Grade.B         
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Li").ID,
                        CourseID = courses.Single(c => c.Title == "Composition").CourseID,
                        Grade = Grade.B         
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Justice").ID,
                        CourseID = courses.Single(c => c.Title == "Literature").CourseID,
                        Grade = Grade.B         
                     }
                };
    
                foreach (Enrollment e in enrollments)
                {
                    var enrollmentInDataBase = context.Enrollments.Where(
                        s =>
                             s.Student.ID == e.StudentID &&
                             s.Course.CourseID == e.CourseID).SingleOrDefault();
                    if (enrollmentInDataBase == null)
                    {
                        context.Enrollments.Add(e);
                    }
                }
                context.SaveChanges();
            }
        }
    }
    

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

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

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

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

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

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

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

    엔터티를 만드는 Enrollment 코드에서는 컬렉션을 만드는 코드에서 students 해당 속성을 설정하지 않았지만 컬렉션의 엔터티에 값이 있다고 가정 ID 합니다.

    new Enrollment { 
        StudentID = students.Single(s => s.LastName == "Alexander").ID, 
        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID, 
        Grade = Grade.A 
    },
    

    컬렉션을 호출 SaveChanges studentsID 때 값이 ID 설정되므로 여기에서 속성을 사용할 수 있습니다. EF는 데이터베이스에 엔터티를 삽입할 때 자동으로 기본 키 값을 가져오고 메모리에 있는 엔터티의 속성을 업데이트합니다 ID .

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

    foreach (Enrollment e in enrollments)
    {
        var enrollmentInDataBase = context.Enrollments.Where(
            s => s.Student.ID == e.Student.ID &&
                 s.Course.CourseID == e.Course.CourseID).SingleOrDefault();
        if (enrollmentInDataBase == null)
        {
            context.Enrollments.Add(e);
        }
    }
    
  2. 프로젝트를 빌드합니다.

첫 번째 마이그레이션 실행

명령을 실행하면 add-migration 마이그레이션에서 데이터베이스를 처음부터 만드는 코드를 생성했습니다. 이 코드는 타임스탬프>_InitialCreate.cs 파일<의 Migrations 폴더에도 있습니다. 클래스의 InitialCreate 메서드는 Up 데이터 모델 엔터티 집합에 해당하는 데이터베이스 테이블을 만들고 메서드는 Down 이를 삭제합니다.

public partial class InitialCreate : DbMigration
{
    public override void Up()
    {
        CreateTable(
            "dbo.Course",
            c => new
                {
                    CourseID = c.Int(nullable: false),
                    Title = c.String(),
                    Credits = c.Int(nullable: false),
                })
            .PrimaryKey(t => t.CourseID);
        
        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.Student",
            c => new
                {
                    ID = c.Int(nullable: false, identity: true),
                    LastName = c.String(),
                    FirstMidName = c.String(),
                    EnrollmentDate = c.DateTime(nullable: false),
                })
            .PrimaryKey(t => t.ID);
        
    }
    
    public override void Down()
    {
        DropForeignKey("dbo.Enrollment", "StudentID", "dbo.Student");
        DropForeignKey("dbo.Enrollment", "CourseID", "dbo.Course");
        DropIndex("dbo.Enrollment", new[] { "StudentID" });
        DropIndex("dbo.Enrollment", new[] { "CourseID" });
        DropTable("dbo.Student");
        DropTable("dbo.Enrollment");
        DropTable("dbo.Course");
    }
}

마이그레이션에서는 마이그레이션을 위한 데이터 모델 변경을 구현하기 위해 Up 메서드를 호출합니다. 업데이트를 롤백하는 명령을 입력하면 마이그레이션에서 Down 메서드를 호출합니다.

명령을 입력할 때 생성된 초기 마이그레이션입니다 add-migration InitialCreate . 매개 변수(InitialCreate 예제에서)는 파일 이름에 사용되며 원하는 대로 될 수 있습니다. 일반적으로 마이그레이션에서 수행되는 작업을 요약하는 단어 또는 구를 선택합니다. 예를 들어 이후 마이그레이션의 이름을 “AddDepartmentTable”로 지정할 수도 있습니다.

데이터베이스가 이미 존재할 때 초기 마이그레이션을 만든 경우 데이터베이스 만들기 코드가 생성되지만 데이터베이스는 이미 데이터 모델과 일치하기 때문에 실행할 필요는 없습니다. 데이터베이스가 아직 없는 다른 환경에 앱을 배포하는 경우 이 코드를 실행하여 데이터베이스를 만들기 때문에 먼저 테스트하는 것이 좋습니다. 따라서 마이그레이션에서 처음부터 새로 만들 수 있도록 연결 문자열 데이터베이스의 이름을 변경했습니다.

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

    update-database

    update-database 명령은 메서드를 Up 실행하여 데이터베이스를 만든 다음 데이터베이스를 Seed 채우는 메서드를 실행합니다. 다음 섹션에서 볼 수 있듯이 애플리케이션을 배포한 후 프로덕션 환경에서 동일한 프로세스가 자동으로 실행됩니다.

  2. 서버 탐색기를 사용하여 첫 번째 자습서에서와 같이 데이터베이스를 검사하고 애플리케이션을 실행하여 모든 항목이 이전과 동일하게 작동하는지 확인합니다.

Azure에 배포

지금까지 애플리케이션은 개발 컴퓨터의 IIS Express에서 로컬로 실행되었습니다. 다른 사용자가 인터넷을 통해 사용할 수 있도록 하려면 웹 호스팅 공급자에 배포해야 합니다. 자습서의 이 섹션에서는 Azure에 배포합니다. 이 섹션은 선택 사항입니다. 이 작업을 건너뛰고 다음 자습서를 계속 진행하거나 이 섹션의 지침을 원하는 다른 호스팅 공급자에 맞게 조정할 수 있습니다.

Code First 마이그레이션을 사용하여 데이터베이스 배포

데이터베이스를 배포하려면 Code First 마이그레이션 사용합니다. Visual Studio에서 배포에 대한 설정을 구성하는 데 사용하는 게시 프로필을 만들 때 데이터베이스 업데이트라는 확인란을 선택합니다. 이 설정을 사용하면 Code First에서 이니셜라이저 클래스를 사용하도록 MigrateDatabaseToLatestVersion 배포 프로세스가 대상 서버에서 애플리케이션 Web.config 파일을 자동으로 구성합니다.

Visual Studio는 프로젝트를 대상 서버에 복사하는 동안 배포 프로세스 중에 데이터베이스를 사용하여 아무 작업도 수행하지 않습니다. 배포된 애플리케이션을 실행하고 배포 후 처음으로 데이터베이스에 액세스하는 경우 Code First는 데이터베이스가 데이터 모델과 일치하는지 확인합니다. 일치하지 않는 경우 Code First는 데이터베이스를 자동으로 만들거나(아직 존재하지 않는 경우) 데이터베이스 스키마를 최신 버전으로 업데이트합니다(데이터베이스가 존재하지만 모델과 일치하지 않는 경우). 애플리케이션이 Migrations Seed 메서드를 구현하는 경우 데이터베이스를 만들거나 스키마를 업데이트한 후에 메서드가 실행됩니다.

마이그레이션 메서드는 Seed 테스트 데이터를 삽입합니다. 프로덕션 환경에 배포하는 경우 프로덕션 데이터베이스에 삽입하려는 데이터만 삽입하도록 메서드를 변경 Seed 해야 합니다. 예를 들어 현재 데이터 모델에서는 실제 과정이지만 개발 데이터베이스에 가상의 학생이 있을 수 있습니다. 개발에서 둘 다 로드하는 메서드를 Seed 작성한 다음 프로덕션 환경에 배포하기 전에 가상의 학생을 주석으로 처리할 수 있습니다. 또는 과정만 로드하는 메서드를 Seed 작성하고 애플리케이션의 UI를 사용하여 테스트 데이터베이스에 가상의 학생을 수동으로 입력할 수 있습니다.

Azure 계정 가져오기

Azure 계정이 필요합니다. 아직 구독이 없지만 Visual Studio 구독이 있는 경우 구독 혜택을 활성화할 수 있습니다. 그렇지 않으면 몇 분 만에 평가판 계정을 만들 수 있습니다. 자세한 내용은 Azure 평가판을 참조하세요.

Azure에서 웹 사이트 및 SQL 데이터베이스 만들기

Azure의 웹앱은 공유 호스팅 환경에서 실행됩니다. 즉, 다른 Azure 클라이언트와 공유되는 VM(가상 머신)에서 실행됩니다. 공유 호스팅 환경은 클라우드에서 시작하는 저렴한 방법입니다. 나중에 웹 트래픽이 증가하는 경우 애플리케이션은 전용 VM에서 실행하여 필요에 맞게 확장할 수 있습니다. Azure 앱 Service의 가격 책정 옵션에 대해 자세히 알아보려면 App Service 가격 책정을 읽어보세요.

Azure SQL 데이터베이스에 데이터베이스를 배포합니다. SQL Database는 SQL Server 기술을 기반으로 하는 클라우드 기반 관계형 데이터베이스 서비스입니다. SQL Server와 함께 작동하는 도구 및 애플리케이션도 SQL 데이터베이스에서 작동합니다.

  1. Azure 관리 포털의 왼쪽 탭에서 리소스 만들기를 선택한 다음 새 창(또는 블레이드)에서 모두 보기를 선택하여 사용 가능한 모든 리소스를 확인합니다. 모든 항목 블레이드의 웹 섹션에서 웹앱 + SQL선택합니다. 마지막으로 만들기를 선택합니다.

    Azure Portal에서 리소스 만들기

    웹앱 + SQL 리소스를 만드는 양식이 열립니다.

  2. 애플리케이션의 고유 URL로 사용할 문자열을 앱 이름 상자에 입력합니다. 전체 URL은 여기에 입력한 항목과 Azure 앱 Services(.azurewebsites.net)의 기본 도메인으로 구성됩니다. 앱 이름을 이미 사용하는 경우 마법사에서 빨간색으로 알 수 있습니다. 앱 이름은 사용할 수 없습니다. 앱 이름을 사용할 수 있는 경우 녹색 확인 표시가 표시됩니다.

  3. 구독 상자에서 App Service가 상주할 Azure 구독을 선택합니다.

  4. 리소스 그룹 텍스트 상자에서 리소스 그룹을 선택하거나 새 리소스 그룹을 만듭니다. 이 설정은 웹 사이트에서 실행할 데이터 센터를 지정합니다. 리소스 그룹에 대한 자세한 내용은 리소스 그룹을 참조하세요.

  5. App Service 섹션, 새로 만들기를 클릭하고 App Service 계획(App Service와 동일한 이름), 위치가격 책정 계층(무료 옵션 있음)을 입력하여 새 App Service 계획을 만듭니다.

  6. SQL Database를 클릭한 다음 새 데이터베이스 만들기를 선택하거나 기존 데이터베이스를 선택합니다.

  7. 이름 상자에 데이터베이스의 이름을 입력합니다.

  8. 대상 서버 상자를 클릭한 다음 새 서버 만들기를 선택합니다. 또는 이전에 서버를 만든 경우 사용 가능한 서버 목록에서 해당 서버를 선택할 수 있습니다.

  9. 가격 책정 계층 섹션을 선택하고 무료를 선택합니다. 추가 리소스가 필요한 경우 언제든지 데이터베이스를 확장할 수 있습니다. Azure SQL 가격 책정에 대한 자세한 내용은 Azure SQL Database 가격 책정을 참조하세요.

  10. 필요에 따라 데이터 정렬을 수정합니다.

  11. 관리자 SQL 관리자 사용자 이름SQL 관리자 암호를 입력합니다.

    • 새 SQL Database 서버를 선택한 경우 나중에 데이터베이스에 액세스할 때 사용할 새 이름과 암호를 정의합니다.
    • 이전에 만든 서버를 선택한 경우 해당 서버에 대한 자격 증명을 입력합니다.
  12. Application Insights를 사용하여 App Service에 원격 분석 수집을 사용하도록 설정할 수 있습니다. 구성이 거의 없는 Application Insights는 중요한 이벤트, 예외, 종속성, 요청 및 추적 정보를 수집합니다. Application Insights에 대한 자세한 내용은 Azure Monitor를 참조하세요.

  13. 맨 아래에서 만들기를 클릭하여 완료되었음을 나타냅니다.

    관리 포털이 대시보드 페이지로 돌아오면 페이지 맨 위에 있는 알림 영역에 사이트가 만들어지고 있음을 보여 줍니다. 잠시 후(일반적으로 1분 미만) 배포에 성공했다는 알림이 표시됩니다. 왼쪽 탐색 모음에서 새 App Service가 App Services 섹션에 나타나고 새 SQL 데이터베이스가 SQL 데이터베이스 섹션에 나타납니다.

Azure에 앱 배포

  1. Visual Studio의 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 상황에 맞는 메뉴에서 게시를 선택합니다.

  2. 게시 대상 선택 페이지에서 App Service를 선택한 다음 기존 서비스를 선택한 다음 게시를 선택합니다.

    게시 대상 페이지 선택

  3. 이전에 Visual Studio에서 Azure 구독을 추가하지 않은 경우 화면에서 단계를 수행합니다. 이러한 단계를 통해 Visual Studio는 App Services 목록에 웹 사이트가 포함되도록 Azure 구독에 연결할 수 있습니다.

  4. App Service 페이지에서 App Service를 추가한 구독을 선택합니다. 보기에서 리소스 그룹을 선택합니다. App Service를 추가한 리소스 그룹을 확장한 다음 App Service를 선택합니다. 확인을 선택하여 앱을 게시합니다.

  5. 출력 창에는 수행된 배포 작업이 표시되고 배포가 성공적으로 완료되었다고 보고합니다.

  6. 배포에 성공하면 기본 브라우저가 배포된 웹 사이트의 URL로 자동으로 열립니다.

    Students_index_page_with_paging

    이제 앱이 클라우드에서 실행되고 있습니다.

이 시점에서 Code First 마이그레이션 실행(앱 시작 시 실행)을 선택했기 때문에 SchoolContext 데이터베이스가 Azure SQL 데이터베이스에 만들어졌습니다. 배포된 웹 사이트의 Web.config 파일이 변경되었으므로 MigrateDatabaseToLatestVersion 이니셜라이저는 코드가 데이터베이스에서 데이터를 처음 읽거나 쓸 때(학생 탭을 선택할 때 발생) 실행됩니다.

Web.config 파일 발췌

또한 배포 프로세스는 Code First 마이그레이션 데이터베이스 스키마를 업데이트하고 데이터베이스를 시드하는 데 사용할 새 연결 문자열(SchoolContext_DatabasePublish)를 만들었습니다.

Web.config 파일의 연결 문자열

ContosoUniversity\obj\Release\Package\PackageTmp\Web.config에서 사용자 컴퓨터에서 배포된 버전의 Web.config 파일을 찾을 수 있습니다. FTP를 사용하여 배포된 Web.config 파일 자체에 액세스할 수 있습니다. 지침은 Visual Studio를 사용하여 ASP.NET 웹 배포: 코드 업데이트 배포를 참조하세요. "FTP 도구를 사용하려면 FTP URL, 사용자 이름 및 암호의 세 가지가 필요합니다."로 시작하는 지침을 따릅니다.

참고 항목

웹앱은 보안을 구현하지 않으므로 URL을 찾은 사람은 누구나 데이터를 변경할 수 있습니다. 웹 사이트를 보호하는 방법에 대한 지침은 멤버 자격, OAuth 및 SQL 데이터베이스를 사용하여 Azure에 보안 ASP.NET MVC 앱 배포를 참조하세요. Visual Studio에서 Azure 관리 포털 또는 서버 탐색기를 사용하여 서비스를 중지하여 다른 사용자가 사이트를 사용하지 못하도록 할 수 있습니다.

앱 서비스 중지 메뉴 항목

고급 마이그레이션 시나리오

이 자습서와 같이 마이그레이션을 자동으로 실행하여 데이터베이스를 배포하고 여러 서버에서 실행되는 웹 사이트에 배포하는 경우 여러 서버가 동시에 마이그레이션을 실행하려고 할 수 있습니다. 마이그레이션은 원자성이므로 두 서버가 동일한 마이그레이션을 실행하려고 하면 하나는 성공하고 다른 서버는 실패합니다(작업을 두 번 수행할 수 없다고 가정). 이 시나리오에서 이러한 문제를 방지하려면 마이그레이션을 수동으로 호출하고 고유한 코드를 설정하여 한 번만 발생하도록 할 수 있습니다. 자세한 내용은 Rowan Miller의 블로그 및 Migrate.exe 코드에서 마이그레이션 실행 및 스크립팅(명령줄에서 마이그레이션 실행)을 참조하세요.

다른 마이그레이션 시나리오에 대한 자세한 내용은 Migrations Screencast 시리즈를 참조 하세요.

특정 마이그레이션 업데이트

update-database -target MigrationName

update-database -target MigrationName 명령은 대상 마이그레이션을 실행합니다.

데이터베이스에 대한 마이그레이션 변경 무시

Add-migration MigrationName -ignoreChanges

ignoreChanges 는 현재 모델을 스냅샷으로 사용하여 빈 마이그레이션을 만듭니다.

Code First 이니셜라이저

배포 섹션에서 MigrateDatabaseToLatestVersion 이니셜라이저가 사용되는 것을 보았습니다. Code First는 CreateDatabaseIfNotExists(기본값), DropCreateDatabaseIfModelChanges(이전에 사용한) 및 DropCreateDatabaseAlways를 비롯한 다른 이니셜라이저도 제공합니다. 이니셜라이저는 DropCreateAlways 단위 테스트 조건을 설정하는 데 유용할 수 있습니다. 또한 고유한 이니셜라이저를 작성할 수 있으며 애플리케이션이 데이터베이스에서 읽거나 데이터베이스에 쓸 때까지 기다리지 않으려는 경우 이니셜라이저를 명시적으로 호출할 수 있습니다.

이니셜라이저 에 대한 자세한 내용은 Entity Framework Code First 의 데이터베이스 이니셜라이저 이해와 도서 프로그래밍 엔터티 프레임워크: Julie Lerman 및 Rowan Miller의 Code First 6장을 참조하세요.

코드 가져오기

완료된 프로젝트 다운로드

추가 리소스

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

다음 단계

이 자습서에서는 다음을 수행합니다.

  • Code First 마이그레이션 사용
  • Azure에서 앱 배포(선택 사항)

다음 문서로 이동하여 ASP.NET MVC 애플리케이션에 대한 보다 복잡한 데이터 모델을 만드는 방법을 알아봅니다.