파트 8: ASP.NET Core MVC - 새로운 필드 추가하기

등록일시: 2016-07-08 08:00,  수정일시: 2016-09-13 22:57
조회수: 4,774
이 문서는 ASP.NET Core MVC 기술을 널리 알리고자 하는 개인적인 취지로 제공되는 번역문서입니다. 이 문서에 대한 모든 저작권은 마이크로소프트에 있으며 요청이 있을 경우 언제라도 게시가 중단될 수 있습니다. 번역 내용에 오역이 존재할 수 있고 주석은 번역자 개인의 의견일 뿐이며 마이크로소프트는 이에 관한 어떠한 보장도 하지 않습니다. 번역이 완료된 이후에도 대상 제품 및 기술이 개선되거나 변경됨에 따라 원문의 내용도 변경되거나 보완되었을 수 있으므로 주의하시기 바랍니다.
이번 파트에서는 Entity Framework Code First 마이그레이션을 이용해서 모델에 새로운 필드를 추가하고 변경된 사항을 데이터베이스에 반영해봅니다.

이번 파트에서는 Entity Framework Code First 마이그레이션을 이용해서 모델에 새로운 필드를 추가하고 변경된 사항을 데이터베이스에 반영해봅니다.

Entity Framework Code First를 이용해서 데이터베이스를 자동으로 생성하면, Code First가 생성된 데이터베이스 스키마와 그에 대응하는 모델 클래스가 서로 일치하는지 여부를 지속적으로 추적하기 위한 테이블을 데이터베이스에 함께 추가합니다. 그리고 그 이후부터 데이터베이스 스키마와 모델 클래스가 일치하지 않으면 Entity Framework가 예외를 던집니다. 결과적으로 혹시라도 런타임에 뒤늦게 발견될 수도 있는 (모호한 오류로 인한) 문제점을 미리 개발 시점에 손쉽게 파악할 수 있습니다.

Movie 모델에 Rating 속성 추가하기

먼저 Models/Movie.cs 파일을 열고 Rating 속성을 추가합니다:

public class Movie
{
    public int ID { get; set; }
    public string Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    public string Genre { get; set; }
    public decimal Price { get; set; }
    public string Rating { get; set; }
}

그리고 응용 프로그램을 빌드합니다 (Ctrl+Shift+B).

이 작업으로 인해서 Movie 클래스에 새로운 필드가 추가되었으므로 매개변수에 지정된 바인딩 화이트 리스트에도 이 새로운 필드를 추가해야 합니다. Create 액션 메서드와 Edit 액션 메서드에 지정된 [Bind] 어트리뷰트를 수정해서 Rating 속성을 추가합니다:

[Bind("ID,Title,ReleaseDate,Genre,Price,Rating")]

또한, 브라우저 뷰에서 새로운 Rating 속성을 출력하거나 생성하고 편집하려면 뷰 템플릿도 수정해야 합니다.

다음과 같이 /Views/Movies/Index.cshtml  파일을 수정해서 Rating 필드를 추가합니다:

<table class="table">
    <tr>
        <th>
            @@Html.DisplayNameFor(model => model.movies[0].Genre)
        </th>
        <th>
            @@Html.DisplayNameFor(model => model.movies[0].Price)
        </th>
        <th>
            @@Html.DisplayNameFor(model => model.movies[0].ReleaseDate)
        </th>
        <th>
            @@Html.DisplayNameFor(model => model.movies[0].Title)
        </th>
        <th>
            @@Html.DisplayNameFor(model => model.movies[0].Rating)
        </th>
        <th></th>
    </tr>
    <tbody>
        @@foreach (var item in Model.movies)
        {
            <tr>
                <td>
                    @@Html.DisplayFor(modelItem => item.Genre)
                </td>
                <td>
                    @@Html.DisplayFor(modelItem => item.Price)
                </td>
                <td>
                    @@Html.DisplayFor(modelItem => item.ReleaseDate)
                </td>
                <td>
                    @@Html.DisplayFor(modelItem => item.Title)
                </td>
                <td>
                    @@Html.DisplayFor(modelItem => item.Rating)
                </td>

그리고 /Views/Movies/Create.cshtml  파일에도 Rating 필드를 추가합니다. 다음 그림처럼 간단하게 "form-group" CSS 클래스가 지정된 다른 DIV 태그를 복사해서 붙여 넣은 다음, 인텔리센스의 도움을 받아서 필드만 변경하면 됩니다. 인텔리센스는 태그 헬퍼를 정상적으로 잘 지원합니다.

그러나 새로운 필드를 데이터베이스에 반영하기 전까지는 응용 프로그램을 실행할 수 없습니다. 지금 상태로 응용 프로그램을 실행하면 다음과 같이 SqlException 발생합니다:

이런 오류가 발생하는 이유는 변경된 Movie 모델 클래스와 기존 데이터베이스의 Movie 테이블 스키마가 서로 일치하지 않기 때문입니다. (즉, 데이터베이스의 테이블에 아직 Rating 컬럼이 없습니다.)

이 오류를 해결하기 위한 접근방법이 몇 가지 존재합니다:

  1. Entity Framework가 새로운 모델 클래스의 스키마를 기반으로 자동으로 데이터베이스를 재생성하도록 구성할 수 있습니다. 이 방식은 모델과 데이터베이스 양쪽 모두를 신속하게 변경할 수 있기 때문에 테스트 데이터베이스를 이용해서 한창 개발이 진행 중인 초기에 매우 편리합니다. 그러나 데이터베이스에 존재하던 기존 데이터가 모두 사라지므로, 절대로 운영 데이터베이스에서는 사용하면 안된다는 단점이 있습니다! 이니셜라이저를 이용해서 데이터베이스에 자동으로 테스트 데이터를 시드하면 생산적으로 응용 프로그램을 개발할 수 있습니다.
  2. 명시적으로 기존 데이터베이스의 스키마를 변경해서 모델 클래스와 일치시킬 수 있습니다. 이 방식의 장점은 기존 데이터를 그대로 유지할 수 있다는 것입니다. 직접 수작업으로 데이터베이스를 변경할 수도 있고 데이터베이스 변경 스크립트를 작성해서 필요한 작업을 수행할 수도 있습니다.
  3. Code First 마이그레이션을 이용해서 데이터베이스의 스키마를 갱신할 수 있습니다.

본문에서는 이 세 가지 방법 중, Code First 마이그레이션 방식을 살펴봅니다.

그러려면 먼저 새로 추가된 컬럼에도 값을 제공할 수 있도록 SeedData 클래스를 수정해야 합니다. 다음 예제 코드에서 볼 수 있는 것처럼 각각의 new Movie 관련 코드들을 모두 수정해주면 됩니다.

     new Movie
     {
         Title = "When Harry Met Sally",
         ReleaseDate = DateTime.Parse("1989-1-11"),
         Genre = "Romantic Comedy",
         Rating = "R",
         Price = 7.99M
     },

경고

반드시 dotnet ef 명령을 실행하기 전에 IIS Express를 중지해야 합니다. To Stop IIS Express를 참고하시기 바랍니다.

작업을 마쳤으면 솔루션을 빌드하고 명령 프롬프트를 엽니다. 그리고 다음 명령을 입력합니다:

역주: 아쉽지만 이 부분에 대한 원문의 설명은 많이 불친절한 편입니다. 본문에서 방금 설명한 것처럼 이 명령은 기존의 패키지 관리자 콘솔이 아닌 명령 프롬프트에서 입력해야 합니다. 명령 프롬프트를 여는 구체적인 요령이 기억나지 않는 분들은 지난 파트를 참고하시기 바랍니다. 그리고 다음 명령을 입력하기 전에 먼저 기존 데이터를 모두 삭제하는 것이 자습서를 따라하시기에 편합니다.

dotnet ef migrations add Rating
dotnet ef database update

이 명령들 중에서 첫 번째 migrations add 명령은 마이그레이션 프레임워크에게 응용 프로그램의 현재 Movie 모델과 데이터베이스의 현재 Movie DB 스키마를 검토해서 데이터베이스를 새로운 모델로 마이그레이션 하는데 필요한 코드를 생성하도록 지시합니다. 그리고 이 명령에 사용된 "Rating"이라는 이름은 임의대로 지정한 이름으로, 마이그레이션 파일의 이름을 구성하는데 사용됩니다. 따라서 마이그레이션 단계를 잘 표현할 수 있는 의미 있는 이름을 지정하는 것이 좋습니다.

데이터베이스에 존재하는 모든 레코드를 삭제하고 이 명령을 수행하면, 이니셜라이저가 Rating 필드가 포함된 데이터를 데이터베이스에 생성해줍니다. 브라우저에서 delete 링크를 하나씩 클릭하거나 SSOX를 이용하면 레코드를 삭제할 수 있습니다.

이제 응용 프로그램을 실행하고 Rating 필드를 포함한 영화 정보를 생성하거나 수정하고 또는 출력해보면서 동작을 확인해보시기 바랍니다. 그러려면 Edit, Details, 그리고 Delete 뷰 템플릿에도 같은 방식으로 Rating 필드를 추가해야 합니다.