다음을 통해 공유


새 데이터베이스에 대한 Code First

이 비디오 및 단계별 연습에서는 새 데이터베이스를 대상으로 하는 Code First 개발을 소개합니다. 이 시나리오에는 존재하지 않고 Code First가 만들 데이터베이스 또는 Code First가 새 테이블을 추가할 빈 데이터베이스를 대상으로 하는 작업이 포함됩니다. Code First를 사용하면 C# 또는 VB.NET 클래스를 사용해 모델을 정의할 수 있습니다. 클래스 및 속성의 특성을 사용하거나 흐름 API를 사용하여 필요에 따라 추가 구성을 수행할 수 있습니다.

비디오 보기

이 비디오에서는 새 데이터베이스를 대상으로 하는 Code First 개발을 소개합니다. 이 시나리오에는 존재하지 않고 Code First가 만들 데이터베이스 또는 Code First가 새 테이블을 추가할 빈 데이터베이스를 대상으로 하는 작업이 포함됩니다. Code First를 사용하면 C# 또는 VB.NET 클래스를 사용해 모델을 정의할 수 있습니다. 클래스 및 속성의 특성을 사용하거나 흐름 API를 사용하여 필요에 따라 추가 구성을 수행할 수 있습니다.

작성자: Rowan Miller

비디오: WMV | MP4 | WMV(ZIP)

필수 구성 요소

이 연습을 완료하려면 Visual Studio 2010 또는 Visual Studio 2012 이상이 설치되어 있어야 합니다.

Visual Studio 2010을 사용하는 경우 NuGet도 설치해야 합니다.

1. 애플리케이션 만들기

작업을 간단하게 유지하기 위해 Code First를 사용하여 데이터 액세스를 수행하는 기본 콘솔 애플리케이션을 빌드합니다.

  • Visual Studio를 엽니다.
  • 파일 -> 새로 만들기 -> 프로젝트
  • 왼쪽 메뉴에서 Windows를 선택하고 콘솔 애플리케이션을 선택합니다.
  • 이름으로 CodeFirstNewDatabaseSample을 입력합니다.
  • 확인을 선택합니다.

2. 모델 만들기

클래스를 사용하여 매우 간단한 모델을 정의해 보겠습니다. Program.cs 파일에서 정의하고 있지만 실제 애플리케이션에서는 클래스를 별도의 파일과 잠재적으로 별도인 프로젝트로 분할하게 됩니다.

Program.cs의 Program 클래스 정의 아래에 다음의 두 클래스가 추가됩니다.

public class Blog
{
    public int BlogId { get; set; }
    public string Name { get; set; }

    public virtual List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public virtual Blog Blog { get; set; }
}

두 가지 탐색 속성(Blog.Posts 및 Post.Blog)을 가상으로 만드는 것을 알 수 있습니다. 이렇게 하면 Entity Framework의 지연 로드 기능이 사용하도록 설정됩니다. 지연 로드는 이러한 속성에 액세스하려고 할 때 해당 속성의 콘텐츠가 데이터베이스에서 자동으로 로드됨을 의미합니다.

3. 컨텍스트 만들기

이제 데이터베이스와의 세션을 나타내는 파생 컨텍스트를 정의하여 데이터를 쿼리하고 저장할 수 있습니다. System.Data.Entity.DbContext에서 파생되는 컨텍스트를 정의하고 모델의 각 클래스에 대해 유형이 지정된 DbSet<TEntity>를 공개합니다.

이제 Entity Framework의 형식을 사용하기 시작했으므로 EntityFramework NuGet 패키지를 추가해야 합니다.

  • 프로젝트 –> NuGet 패키지 관리… 참고: NuGet 패키지 관리… 옵션이 없는 경우 최신 버전의 NuGet을 설치해야 합니다.
  • 온라인 탭을 선택합니다.
  • EntityFramework 패키지를 선택합니다.
  • 설치를 클릭합니다.

Program.cs의 맨 위쪽에 System.Data.Entity에 대한 using 문을 추가합니다.

using System.Data.Entity;

Program.cs의 Post 클래스 아래쪽에 다음과 같은 파생 컨텍스트를 추가합니다.

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
}

다음은 Program.cs에 포함해야 하는 내용의 전체 목록입니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;

namespace CodeFirstNewDatabaseSample
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }

    public class Blog
    {
        public int BlogId { get; set; }
        public string Name { get; set; }

        public virtual List<Post> Posts { get; set; }
    }

    public class Post
    {
        public int PostId { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }

        public int BlogId { get; set; }
        public virtual Blog Blog { get; set; }
    }

    public class BloggingContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }
        public DbSet<Post> Posts { get; set; }
    }
}

데이터 저장 및 검색을 시작하는 데 필요한 모든 코드입니다. 분명히 뒷 부분에 꽤 많은 내용이 있으며 이에 대해서는 잠시 후에 살펴보겠지만 먼저 실제로 작동하는 모습을 알아보겠습니다.

4. 데이터 읽기 및 쓰기

아래와 같이 Program.cs에서 Main 메서드를 구현합니다. 이 코드는 컨텍스트의 새 인스턴스를 만든 다음, 이를 사용하여 새 블로그를 삽입합니다. 그런 다음 LINQ 쿼리를 사용하여 제목별로 알파벳순으로 정렬된 데이터베이스에서 모든 블로그를 검색합니다.

class Program
{
    static void Main(string[] args)
    {
        using (var db = new BloggingContext())
        {
            // Create and save a new Blog
            Console.Write("Enter a name for a new Blog: ");
            var name = Console.ReadLine();

            var blog = new Blog { Name = name };
            db.Blogs.Add(blog);
            db.SaveChanges();

            // Display all Blogs from the database
            var query = from b in db.Blogs
                        orderby b.Name
                        select b;

            Console.WriteLine("All blogs in the database:");
            foreach (var item in query)
            {
                Console.WriteLine(item.Name);
            }

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }
    }
}

이제 애플리케이션을 실행하고 테스트할 수 있습니다.

Enter a name for a new Blog: ADO.NET Blog
All blogs in the database:
ADO.NET Blog
Press any key to exit...

내 데이터 위치

규칙에 따라 DbContext는 사용자를 위해 데이터베이스를 만들었습니다.

  • 로컬 SQL Express 인스턴스를 사용할 수 있는 경우(Visual Studio 2010에 기본적으로 설치됨) Code First가 해당 인스턴스에 데이터베이스를 만든 것입니다.
  • SQL Express를 사용할 수 없는 경우 Code First는 LocalDB를 시도하고 사용합니다(Visual Studio 2012에 기본적으로 설치됨).
  • 데이터베이스 이름은 파생 컨텍스트의 정규화된 이름을 따서 명명됩니다. 이 경우에는 CodeFirstNewDatabaseSample.BloggingContext입니다.

이는 기본 규칙일 뿐이며 Code First에서 사용하는 데이터베이스를 변경하는 다양한 방법이 있습니다. 자세한 내용은 DbContext에서 모델 및 데이터베이스 연결을 검색하는 방법 항목에서 확인할 수 있습니다. Visual Studio에서 서버 탐색기를 사용하여 이 데이터베이스에 연결할 수 있습니다.

  • 보기 -> 서버 탐색기

  • 데이터 연결을 마우스 오른쪽 단추로 클릭하고 연결 추가…를 선택합니다.

  • 서버 탐색기에서 데이터베이스에 아직 연결하지 않은 경우 Microsoft SQL Server를 데이터 원본으로 선택해야 합니다.

    Select Data Source

  • 설치한 항목에 따라 LocalDB 또는 SQL Express에 연결합니다.

이제 Code First에서 만든 스키마를 검사할 수 있습니다.

Schema Initial

DbContext는 정의한 DbSet 속성을 확인하여 모델에 포함할 클래스를 확인했습니다. 그런 다음 Code First 규칙의 기본 집합을 사용하여 테이블 및 열 이름을 결정하고, 데이터 형식을 결정하고, 기본 키를 찾는 등의 작업을 수행합니다. 이 연습의 뒷부분에서는 이러한 규칙을 재정의하는 방법을 살펴보겠습니다.

5. 모델 변경 처리

이제 모델을 몇 가지 변경해야 하며, 이러한 변경을 수행할 때 데이터베이스 스키마도 업데이트해야 합니다. 이 작업을 수행하기 위해 Code First 마이그레이션(줄여서 마이그레이션)을 사용합니다.

마이그레이션을 사용하면 데이터베이스 스키마를 업그레이드(및 다운그레이드)하는 방법을 설명하는 정렬된 단계 집합을 가질 수 있습니다. 마이그레이션이라고 하는 이러한 각 단계에는 적용할 변경 내용을 설명하는 몇 가지 코드가 포함되어 있습니다. 

첫 번째 단계는 BloggingContext에 Code First 마이그레이션 사용하도록 설정하는 것입니다.

  • 도구 -> 라이브러리 패키지 관리자 -> 패키지 관리자 콘솔

  • 패키지 관리자 콘솔에서 Enable-Migrations 명령을 실행합니다.

  • 두 개의 항목이 포함된 새 Migrations 폴더가 프로젝트에 추가되었습니다.

    • Configuration.cs – 이 파일에는 마이그레이션이 BloggingContext 마이그레이션에 사용할 설정이 포함되어 있습니다. 이 연습에서는 아무것도 변경할 필요가 없지만 여기서는 시드 데이터를 지정하고, 다른 데이터베이스에 공급자를 등록하고, 마이그레이션이 생성되는 네임스페이스를 변경하는 등의 작업을 수행할 수 있습니다.
    • <timestamp>_InitialCreate.cs – 첫 번째 마이그레이션으로, 빈 데이터베이스에서 블로그 및 게시물 테이블을 포함하는 데이터베이스로 전환하기 위해 데이터베이스에 이미 적용된 변경 사항을 나타냅니다. Code First에서 이러한 테이블을 자동으로 만들도록 허용했지만, 마이그레이션에 옵트인했으므로 마이그레이션으로 변환되었습니다. 또한 Code First는 이 마이그레이션이 이미 적용되었음을 로컬 데이터베이스에 기록했습니다. 파일 이름의 타임스탬프는 순서 지정을 위해 사용됩니다.

    이제 모델을 변경하고 블로그 클래스에 Url 속성을 추가해 보겠습니다.

public class Blog
{
    public int BlogId { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }

    public virtual List<Post> Posts { get; set; }
}
  • 패키지 관리자 콘솔에서 Add-Migration AddBlogUrl 명령을 실행합니다. Add-Migration 명령은 마지막 마이그레이션 이후의 변경 내용을 확인하고 발견된 변경 내용과 함께 새 마이그레이션을 스캐폴드합니다. 마이그레이션 이름을 지정할 수 있습니다. 이 경우 마이그레이션 'AddUrl'을 호출합니다. 스캐폴드된 코드에는 문자열 데이터를 저장할 수 있는 Url 열을 dbo 블로그 테이블에 추가해야 한다고 표시됩니다. 필요한 경우 스캐폴드된 코드를 편집할 수 있지만 이 경우에는 필요하지 않습니다.
namespace CodeFirstNewDatabaseSample.Migrations
{
    using System;
    using System.Data.Entity.Migrations;

    public partial class AddUrl : DbMigration
    {
        public override void Up()
        {
            AddColumn("dbo.Blogs", "Url", c => c.String());
        }

        public override void Down()
        {
            DropColumn("dbo.Blogs", "Url");
        }
    }
}
  • 패키지 관리자 콘솔에서 Update-Database 명령을 실행합니다. 이 명령은 보류 중인 모든 마이그레이션을 데이터베이스에 적용합니다. InitialCreate 마이그레이션이 이미 적용되었으므로 마이그레이션에서 새 AddUrl 마이그레이션만 적용됩니다. 팁: Update-Database 호출할 때 –Verbose 스위치를 사용하여 데이터베이스에 대해 실행 중인 SQL을 볼 수 있습니다.

이제 새 URL 열이 데이터베이스의 블로그 테이블에 추가됩니다.

Schema With Url

6. 데이터 주석

지금까지는 EF가 기본 규칙을 사용하여 모델을 검색하도록 허용했지만, 클래스가 규칙을 따르지 않고 추가 구성을 수행할 수 있어야 하는 경우가 있습니다. 여기에는 두 가지 옵션이 있습니다. 이 섹션의 데이터 주석과 다음 섹션의 흐름 API를 살펴보겠습니다.

  • 모델에 User 클래스를 추가해 보겠습니다.
public class User
{
    public string Username { get; set; }
    public string DisplayName { get; set; }
}
  • 또한 파생 컨텍스트에 집합을 추가해야 합니다.
public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
    public DbSet<User> Users { get; set; }
}
  • 마이그레이션을 추가하려고 하면 "EntityType 'User'에 키가 정의되지 않았습니다. EntityType에 키가 정의되어 있지 않습니다."라는 오류 메시지가 표시됩니다. EF는 Username이 사용자의 기본 키여야 한다는 것을 알 수 없기 때문입니다.
  • 이제 데이터 주석을 사용할 것이므로 Program.cs 상단에 using 문을 추가해야 합니다.
using System.ComponentModel.DataAnnotations;
  • 이제 Username 속성에 주석을 추가하여 기본 키임을 식별합니다.
public class User
{
    [Key]
    public string Username { get; set; }
    public string DisplayName { get; set; }
}
  • Add-Migration AddUser 명령을 사용해 마이그레이션을 스캐폴드하여 이러한 변경 내용을 데이터베이스에 적용합니다.
  • Update-Database 명령을 실행하여 데이터베이스에 새 마이그레이션을 적용합니다.

이제 새 테이블이 데이터베이스에 추가됩니다.

Schema With Users

EF에서 지원하는 주석의 전체 목록은 다음과 같습니다.

7. Fluent API

이전 섹션에서는 데이터 주석을 사용하여 규칙에 의해 검색된 항목을 보완하거나 재정의하는 방법을 살펴보았습니다. 모델을 구성하는 다른 방법은 Code First Fluent API를 사용하는 것입니다.

대부분의 모델 구성은 간단한 데이터 주석을 사용하여 수행할 수 있습니다. 흐름 API는 데이터 주석으로는 불가능한 고급 구성 외에도 데이터 주석이 수행할 수 있는 모든 작업을 다루는 모델 구성을 지정하는 고급 방법입니다. 데이터 주석과 흐름 API를 함께 사용할 수 있습니다.

흐름 API에 액세스하려면 DbContext에서 OnModelCreating 메서드를 재정의합니다. User.DisplayName이 저장된 열의 이름을 display_name 것이라고 가정해 보겠습니다.

  • BloggingContext에서 OnModelCreating 메서드를 다음과 같은 코드로 재정의합니다.
public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .Property(u => u.DisplayName)
            .HasColumnName("display_name");
    }
}
  • Add-Migration ChangeDisplayName 명령을 사용해 마이그레이션을 스캐폴드하여 이러한 변경 내용을 데이터베이스에 적용합니다.
  • Update-Database 명령을 실행하여 데이터베이스에 새 마이그레이션을 적용합니다.

이제 DisplayName 열의 이름이 display_name으로 변경되었습니다.

Schema With Display Name Renamed

요약

이 연습에서는 새 데이터베이스를 사용한 Code First 개발을 살펴보았습니다. 클래스를 사용하여 모델을 정의한 다음, 해당 모델을 사용하여 데이터베이스를 만들고 데이터를 저장하고 검색했습니다. 데이터베이스가 만들어진 후 모델이 발전함에 따라 Code First 마이그레이션을 사용하여 스키마를 변경했습니다. 또한 데이터 주석 및 흐름 API를 사용하여 모델을 구성하는 방법도 알아보았습니다.