EntityFrameworkのデータファーストとDbContextの接続文字列を動的に変える方法

EntityFrameworkはAsp.NET MVCのO/Rマッパーです。

ユーザが Model クラスを作成し、 ビルド時にそれを元にEntityFrameworkがDBとテーブルを作成します。 コードからDBが作成されるので通常これはコードファーストと呼ばれます。

しかし、既存のDBからModelを自動生成する方法もEntityFrameworkには用意されています。 (実際の業務ではこっちの方が多い気がしますね。) これは、DBからコード(Model)を作るのでデータファースと呼ばれます。

DBからModelを作成する方法

では、データファーストにより既存のDBからModelを作成する方法を紹介します。

0.事前準備

ソリューションにDBを作成します。 今回はDB名を TestDB、その中にテーブル:users を用意しておきます。

CREATE TABLE [dbo].[users] (
    [Id]   INT        NOT NULL,
    [name] NCHAR (10) NULL,
    [age]  NCHAR (10) NULL,
    [sex]  NCHAR (10) NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);
1.プロジェクト内にModelsフォルダを作成します。
2.Modelsフォルダで右クリックし「新しい項目を追加」を選択します。
3.「ADO.NET Entity Data Model」を追加します。

名前は適当なものを入力します(ここではTestDBContext)。

最後に DBContext をつけるのが一般的です。

f:id:Turing:20160716160943p:plain

4.「データベースからCode Firstを選択。」

f:id:Turing:20160716161121p:plain

5.「新しい接続」をクリックして、

今回はソリューション内にDBを作ったので、データソースに「Micorosoft SQLServerデータソースファイルを選択」。

f:id:Turing:20160716161224p:plain

f:id:Turing:20160716161620p:plain

データベースファイル名には事前にソリューション内に用意しておいたDBを選択します。

6. 接続設定に名前をつけて次へ。

f:id:Turing:20160716162154p:plain

7.モデルを生成する対象のテーブルをすべて選択します。

f:id:Turing:20160716162415p:plain

8.ModelsフォルダにTestDBContextと各テーブルのModelクラスが追加されます。

f:id:Turing:20160716162615p:plain

できたクラスの中身はこんな感じ。

namespace DBFirstPractice.Models
{
    using System;
    using System.Data.Entity;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Linq;

    public partial class TestDBContext : DbContext
    {
        public TestDBContext()
            : base("name=TestDBContext")
        {
        }

        public virtual DbSet<user> users { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<user>()
                .Property(e => e.name)
                .IsFixedLength();

            modelBuilder.Entity<user>()
                .Property(e => e.age)
                .IsFixedLength();

            modelBuilder.Entity<user>()
                .Property(e => e.sex)
                .IsFixedLength();
        }
    }
}
namespace DBFirstPractice.Models
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity.Spatial;

    public partial class user
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int Id { get; set; }

        [StringLength(10)]
        public string name { get; set; }

        [StringLength(10)]
        public string age { get; set; }

        [StringLength(10)]
        public string sex { get; set; }
    }
}

DBContextの接続文字列を動的に変える方法

下記のようにすることで、 ソース上で動的に接続先を変えることもできます。 (先ほど作成した、users テーブルと同じ構造のテーブルを持つ、  TestDbBackupというDBがあるものとします。)

まず、自動生成されたDBContextのコンストラクタを下記のように変更します。

namespace DBFirstPractice.Models
{
    using System;
    using System.Data.Entity;
    using System.Data.Common;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Linq;

    public partial class TestDBContext : DbContext
    {
        public TestDBContext(DbConnection connection) : base(connection, true)
        {
        }

        public virtual DbSet<user> users { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<user>()
                .Property(e => e.name)
                .IsFixedLength();

            modelBuilder.Entity<user>()
                .Property(e => e.age)
                .IsFixedLength();

            modelBuilder.Entity<user>()
                .Property(e => e.sex)
                .IsFixedLength();
        }
    }
}

次に、DBContextをインスタンスを生成する際にConnectionを設定します。

namespace DBFirstPractice.Controllers
{
    public class HomeController : Controller
    {
        TestDBContext _db;

        public HomeController()
        {
            var connection = DbProviderFactories.GetFactory("System.Data.SqlClient").CreateConnection();
            connection.ConnectionString = "data source=(LocalDB)\\MSSQLLocalDB;attachdbfilename=|DataDirectory|\\TestDbBackup.mdf;integrated security=True;connect timeout=30;MultipleActiveResultSets=True;App=EntityFramework";

            _db = new TestDBContext(connection);
        }

        // GET: Home
        public ActionResult Index()
        {
            List<user> mans = _db.users.Where(u => u.sex == "man").ToList();

            return View();
        }
    }
}

この接続文字列のDataSourceを変更することでソース上で動的に接続するDBを切り替えることができます。