新しいデータベースの Code First

このビデオとステップバイステップのチュートリアルでは、新しいデータベースを対象とした Code First 開発の概要を説明します。 このシナリオには、存在しておらず、Code First によって作成されるデータベース、または Code First で新しいテーブルが追加される空のデータベースをターゲットとする場合が含まれます。 Code First を使用すると、C# または VB.Net クラスを使用してモデルを定義できます。 必要に応じて、クラスおよびプロパティの属性を使用するか、または fluent API を使用して、追加の構成を行うことができます。

ビデオを見る

このビデオでは、新しいデータベースを対象とした Code First 開発の概要を説明します。 このシナリオには、存在しておらず、Code First によって作成されるデータベース、または Code First で新しいテーブルが追加される空のデータベースをターゲットとする場合が含まれます。 Code First を使用すると、C# または VB.Net クラスを使用してモデルを定義できます。 必要に応じて、クラスおよびプロパティの属性を使用するか、または fluent API を使用して、追加の構成を行うことができます。

提供: Rowan Miller

ビデオ: WMV | MP4 | WMV (ZIP)

前提条件

このチュートリアルを実行するには、少なくとも Visual Studio 2010 または Visual Studio 2012 がインストールされている必要があります。

Visual Studio 2010 を使用している場合は、NuGet もインストールされている必要があります。

1. アプリケーションを作成する

わかりやすくするために、Code First を使用してデータ アクセスを実行する基本的なコンソール アプリケーションを構築します。

  • Visual Studio を開きます
  • [ファイル] -> [新規作成] -> [プロジェクト]
  • 左側のメニューから [Windows] を選択し、[コンソール アプリケーション] を選択します。
  • 名前として、「CodeFirstNewDatabaseSample」を入力します
  • [OK] を選択します。

2. モデルを作成する

クラスを使用して、非常に単純なモデルを定義してみましょう。 ここでは、それらを Program.cs ファイルで定義するだけですが、実際のアプリケーションでは、クラスを個別のファイルに分割し、場合によっては個別のプロジェクトに分割します。

Program.cs で、Program クラス定義の下に、次の 2 つのクラスを追加します。

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; }
}

2 つのナビゲーション プロパティ (Blog.Posts と Post.Blog) を仮想化していることがわかるでしょう。 これにより、Entity Framework の遅延読み込み機能が有効になります。 遅延読み込みとは、これらのプロパティにアクセスしようとすると、これらのプロパティの内容がデータベースから自動的に読み込まれることを意味します。

3. コンテキストを作成する

次に、データベースとのセッションを表す派生コンテキストを定義し、データをクエリして保存できるようにします。 System.Data.Entity.DbContext から派生し、モデル内の各クラスの型指定された DbSet<TEntity> を公開するコンテキストを定義します。

これで、Entity Framework の型を使用できるようになったので、EntityFramework NuGet パッケージを追加する必要があります。

  • [プロジェクト] –> [NuGet パッケージの管理] 注: [パッケージの管理] オプションが表示されない場合、最新バージョンの NuGet をインストールする必要があります
  • [オンライン] タブを選択します
  • EntityFramework パッケージを選択します。
  • [インストール]をクリックします。

Program.cs の先頭に、System.Data.Entity の using ステートメントを追加します。

using System.Data.Entity;

Program.cs で、Post クラスの下に、次の 2 つの派生コンテキストを追加します。

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 メソッドを実装します。 このコードでは、コンテキストの新しいインスタンスを作成し、それを使用して新しい Blog を挿入します。 次に、LINQ クエリを使用して、データベースから、Title のアルファベット順に並べ替えられたすべての Blog を取得します。

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 Migrations、または略して Migrations と呼ばれる機能を使用します。

Migrations を使用すると、データベース スキーマをアップグレード (およびダウングレード) する方法を記述する、順序付けされた一連のステップを使用できます。 移行と呼ばれるこれらの各ステップには、適用する変更を記述する何らかのコードが含まれます。 

最初のステップは、BloggingContext に対して Code First Migrations を有効にすることです。

  • [ツール] -> [ライブラリ パッケージ マネージャー] -> [パッケージ マネージャー コンソール]

  • パッケージ マネージャー コンソールで Enable-Migrations コマンドを実行します

  • 次の 2 つの項目を含む新しい Migrations フォルダーがプロジェクトに追加されます。

    • Configuration.cs – このファイルには、BloggingContext を移行するために Migrations で使用される設定が含まれます。 このチュートリアルでは何も変更する必要はありませんが、ここでは、シード データの指定、他のデータベースのプロバイダーの登録、移行が生成される名前空間の変更を行うことができます。
    • <timestamp>_InitialCreate.cs – これは最初の移行であり、データベースを、空のデータベースから、Blogs および Post テーブルを含むデータベースに変更するために、データベースに既に適用されている変更を表します。 これらのテーブルは Code First で自動的に作成されますが、ここでは、Migrations をオプトインしたので、移行に変換されました。 Code First では、この移行が既に適用されていることもローカル データベースに記録されています。 ファイル名のタイムスタンプは、順序付けの目的で使用されます。

    ここで、モデルに変更を加え、URL プロパティを Blog クラスに追加します。

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 AddUrl コマンドを実行します。 Add-Migration コマンドは、最後の移行以降に行われた変更を確認し、検出された変更で新しい移行をスキャフォールディングします。 移行に名前を付けます。この場合は、移行に 'AddUrl' という名前を付けます。 スキャフォールディングされたコードは、文字列データを保持できる URL 列を dbo.Blogs テーブルに追加する必要があることを示しています。 必要に応じて、スキャフォールディングされたコードを編集できますが、この場合は必要ありません。
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 列が、データベース内の Blogs テーブルに追加されました。

Schema With Url

6. データ注釈

これまで、EF で既定の規則を使用してモデルを検出してきましたが、クラスが規則に従わない場合があり、さらに構成を実行できるようにする必要があります。 このためには 2 つのオプションがあります。このセクションではデータ注釈を、次のセクションでは fluent 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 には、ユーザー名がユーザーの主キーであることを認識する方法がないためです。
  • 以上で、データ注釈を使用するようになったので、using ステートメントを Program.cs の冒頭に追加する必要があります
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

前のセクションでは、データ注釈を使用して、規則により検出されたものを補足またはオーバーライドする方法について説明しました。 モデルを構成するもう 1 つの方法は、Code First fluent API を使用することです。

ほとんどのモデル構成は、簡単なデータ注釈を使用して行うことができます。 fluent API は、モデル構成を指定するためのより高度な方法であり、データ注釈で行うことができるすべての構成に加えて、データ注釈では不可能ないくつかのより高度な構成を行うことができます。 データ注釈と fluent API を一緒に使用することができます。

fluent 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 Migrations を使用して、モデルの進化に合わせてスキーマを変更しました。 さらに、データ注釈と Fluent API を使用してモデルを構成する方法も確認しました。