連載:ASP.NET MVC入門【バージョン3対応】

第2回 Entity Frameworkコード・ファーストでモデル開発

山田 祥寛(http://www.wings.msn.to/
2011/04/21
Page1 Page2 Page3

エンティティをデータベースに接続するコンテキスト・クラス

 エンティティが定義できたところで、この何の変哲もないPOCOをデータベースに接続する――橋渡しの役目を果たすのがコンテキスト・クラス(System.Data.Entity.DbContextクラスの派生クラス)だ。

 まずは、リスト3で具体的な例を確認してみよう。

using System.Data.Entity;

namespace MvcApp.Models
{
  public class MyMvcContext : DbContext
  {
    public DbSet<Book> Books { get; set; } // Booksテーブル
    public DbSet<Review> Reviews { get; set; } // Reviewsテーブル
  }
}
Imports System.Data.Entity

Public Class MyMvcContext : Inherits DbContext
    Public Property Books As DbSet(Of Book) ' Booksテーブル
    Public Property Reviews As DbSet(Of Review) ' Reviewsテーブル
End Class
リスト3 データベースに接続するためのコンテキスト・クラス(上:MyMvcContext.cs、下:MyMvcContext.vb)

 もっとも、橋渡しとはいっても、何ということはない。リスト3のように、エンティティとテーブルとをマッピングするために、DbSet<エンティティ>型のパブリック・プロパティ(名前はエンティティ名の複数形)を定義するだけだ。

 これによって、コンテキスト・クラスMyMvcContextのBooks、Reviewsプロパティは、同名のBooks、Reviewsテーブルにアクセスし、その結果をレコード単位にBook、Reviewエンティティのインスタンスに割り当てることになる。先ほども述べたように、テーブルの各列(フィールド)は、それぞれエンティティの対応するプロパティにマッピングされる。

データベース接続文字列の準備

 これでモデル側の準備は完了だ。続いて、コンテキスト・クラスがデータベースに接続するための接続文字列を「Web.config」ファイルに定義しておこう。

<connectionStrings>
  <add name="MyMvcContext" connectionString="Data Source=|DataDirectory|MyMvc.sdf" providerName="System.Data.SqlServerCe.4.0"/>
  ……中略……
</connectionStrings>
リスト4 データベース接続文字列の定義(Web.config)

 Entity Frameworkコード・ファースト固有のポイントは1点、接続名(name属性)の部分である。Entity Frameworkでは、接続名はコンテキスト・クラスの名前(ここでは「MyMvcContext」)と等しくなければならない。Entity Frameworkは、この命名規約によって接続情報を取得しようとするためだ。

 なお、本稿ではSQL Server Compact 4.0を前提としているので、プロバイダ名は「System.Data.SqlServerCe.4.0」としているが、従来のSQL Serverに接続するならば、「System.Data.SqlClient」とすればよい。

イニシャライザによるテスト・データの準備

 Entity Frameworkでは、モデルの修正が行われた場合に、即座にスキーマの変更をデータベースに反映させ、また、動作確認用のデータを展開するためのイニシャライザという仕組みを提供している。イニシャライザを利用することで、開発者はデータベース側を最後までほとんど意識することなく、モデル(スキーマ)の修正を行えるというわけだ。この機能は、スキーマの変動が激しい開発途上の段階ではとても有効なものだ。

 以下では、モデルの変更があった場合にデータベースを再作成(drop & create)し、テスト・データを投入するためのイニシャライザの作成例である。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;

namespace MvcApp.Models
{
  public class MyMvcInitializer : DropCreateDatabaseIfModelChanges<MyMvcContext>
  {
    protected override void Seed(MyMvcContext context)
    {
      var books = new List<Book> {

        new Book { Isbn = "978-4-8399-3793-5",
                   Title = "HTML5基礎",
                   Price = 2980,
                   Publish="毎日コミュニケーションズ",
                   Published = DateTime.Parse("2011-03-25") },

        new Book { Isbn = "978-4-7741-4663-8",
                   Title = "Ruby on Rails 3プログラミング",
                   Price = 3675, Publish="技術評論社",
                   Published = DateTime.Parse("2011-05-12") },
        ……中略……
      };
      books.ForEach(b => context.Books.Add(b));
      context.SaveChanges();
    }
  }
}
Imports System.Data.Entity

Public Class MyMvcInitializer
  Inherits DropCreateDatabaseIfModelChanges(Of MyMvcContext)

  Protected Overrides Sub Seed(context As MyMvcContext)

    Dim books = New List(Of Book)() From {

      New Book() With { .Isbn = "978-4-8399-3793-5", _
                        .Title = "HTML5基礎", _
                        .Price = 2980, _
                        .Publish = "毎日コミュニケーションズ", _
                        .Published = DateTime.Parse("2011-03-25")},

      New Book() With { .Isbn = "978-4-7741-4663-8", _
                        .Title = "Ruby on Rails 3プログラミング", _
                        .Price = 3675, _
                        .Publish = "技術評論社", _
                        .Published = DateTime.Parse("2011-05-12")},
      ……中略……
    }
    books.ForEach(Function(b) context.Books.Add(b))
    context.SaveChanges()

  End Sub
End Class
リスト5 データベースを初期化するためのイニシャライザ(上:MyMvcInitializer.cs、下:MyMvcInitializer.vb)

 イニシャライザを定義するには、目的に応じて、以下のいずれかのクラス(いずれもSystem.Data.Entity名前空間)を継承すること(リスト5の )。

クラス 概要
CreateDatabaseIfNotExists<T> データベースが存在しない場合のみ生成
DropCreateDatabaseIfModelChanges<T> モデルが変更された場合のみ再生成
DropCreateDatabaseAlways<T> アプリケーション起動時に常にデータベースを再生成
表1 イニシャライザを定義するための基底クラス
「T」はコンテキスト・クラス。

 Seedメソッドは、テスト・データを投入するための処理を表すprotectedメソッドだ(リスト5の )。引数としてコンテキスト・クラスを受け取るので、これを利用して、テーブルにデータを保存すればよい。

 リスト5では、投入すべきデータをList<エンティティ>型で準備し、これをForEachメソッドでコンテキストに流し込んだ後、SaveChangesメソッドでデータベースに反映している。Entity Frameworkによるデータの保存/更新については、別稿「Entity Frameworkにおけるクエリと更新」が詳しいので、こちらも併せて参照してほしい。

 ここでは取りあえず、Booksテーブルに対してのみデータを投入しているが、(もちろん)同じ要領でReviewsテーブルに対してもデータをセット可能だ。

 イニシャライザの準備ができたら、後はGlobal.asaxのApplication_Startメソッドから、アプリケーションに登録するだけだ。

using System.Data.Entity;
using MvcApp.Models;

  ……中略……
protected void Application_Start()

{
  ……中略……

  RegisterRoutes(RouteTable.Routes);

  Database.SetInitializer<MyMvcContext>(new MyMvcInitializer());
}
Imports System.Data.Entity

  ……中略……

Sub Application_Start()

  ……中略……

  RegisterRoutes(RouteTable.Routes);

  Database.SetInitializer(Of MyMvcContext)(New MyMvcInitializer())

End Sub
リスト6 イニシャライザを登録するためのコード(上:Global.asax.cs、下:Global.asax.vb)

 イニシャライザを登録するには、SetInitializerメソッドを呼び出せばよい。

public static void SetInitializer<TContext>(
                        IDatabaseInitializer<TContext> strategy)
SetInitializerメソッドの呼び出し
「TContext」はコンテキストの型、「strategy」はイニシャライザのインスタンス。

 リスト5の例では、引数strategyに対して先ほど作成したMyMvcInitializerオブジェクトをセットしているが、テスト・データの投入を必要としない(Seedメソッドのオーバライドが不要である)場合には、表1でも示したSystem.Data.Entity名前空間のクラスを直接にセットしても構わない。

 例えば、以下のようなコードも可能である。

Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyMvcContext>());
Database.SetInitializer(new DropCreateDatabaseIfModelChanges(Of MyMvcContext)())
リスト7 SetInitializerメソッドの記述例(上:C#、下:VB)

 以上、モデル部分のコードを準備できたところで、いったんメニューの[ビルド]−[ソリューションのビルド]からソリューションをビルドしておこう。さもないと、以降の手順でモデル・クラスなどが認識されないので注意されたい。


 INDEX
  ASP.NET MVC入門【バージョン3対応】
  第2回 Entity Frameworkコード・ファーストでモデル開発
    1.EF 4.1のインストール/モデル・オブジェクトを作成する
  2.コンテキスト・クラス/DB接続文字列の準備/イニシャライザ
    3.スキャフォールディング機能を利用しよう/サンプルの実行
 
インデックス・ページヘ  「ASP.NET MVC入門【バージョン3対応】」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間