C# + FluentMigratorを使って、MS Accessのテーブルスキーマを作成・変更してみた

昔のMS Accessテーブルを引っ張り出してくると、「なぜこのテーブルやカラムがあるのか?」を思い出せない時がありました。

そのため、MS Accessであってもテーブルスキーマのバージョン管理をしたくなりました。

そこで、Rubyで見たMigrationのようなものがC#にないかを探してみたところ、FluentMigratorがありました。
schambers/fluentmigrator · GitHub

ドキュメントを見ると、Jetの文字がありました。MS Access (*.accdb)でも使えるかもしれないと考え、試してみることにしました。
Fluent Interface · schambers/fluentmigrator Wiki · GitHub

 

環境

 

準備

プロジェクトの作成

今回はコンソールアプリケーションプロジェクトを作成しました。(今回は、D:\GitHub\FluentMigrator-sample)

 

FluentMigratorのインストール

FluentMigratorはNuGetでインストールできます。

f:id:thinkAmi:20141106061401p:plain

 

MS Accessテーブルの用意

空っぽの *.accdbファイル(今回は D:\GitHub\FluentMigrator-sample\sample.accdb)を用意します。

 

MS Accessのテーブルスキーマを作成・変更

公式のGetting Startedを参考に、MS Accessを使う上で気になるところを試してみました。
Home · schambers/fluentmigrator Wiki · GitHub

 
マイグレーションごとの内容は、以下の通りです。

No ファイル名 内容
1 Migration2014110601.cs UsersテーブルにID(数値型、主キー)とName(テキスト型)を用意
2 Migration2014110602.cs UsersテーブルのIDをオートナンバー型に変更
3 Migration2014110603.cs UsersテーブルにDescription(メモ型)を追加

 

UsersテーブルにID(数値型)とName(テキスト型)を用意

今回はマイグレーションファイルをまとめることにして、プロジェクトにMigrationsフォルダを作成します。

そして、その中にマイグレーションファイル(Migration2014110601.cs)を作成します。

なお、マイグレーションファイルで使えるメソッドなどは、以下にまとまっていました。
Fluent Interface · schambers/fluentmigrator Wiki · GitHub

using FluentMigrator;

namespace FluentMigrator_sample.Migrations
{
    [Migration(2014110601)]
    public class Migration2014110601 : Migration
    {
        public override void Up()
        {
            Create.Table("Users")
                .WithColumn("ID").AsInt32().PrimaryKey()
                .WithColumn("Name").AsString();
        }

        public override void Down()
        {
            Delete.Table("Users");
        }
    }
}

 

マイグレーションの実行

Migration Runnerとして、

  • Command Line Runner
  • NAnt Runner
  • MSBuild Runner
  • Rake Runner

が用意されていますが、今回は一番手軽なCommand Line Runnerを使ってみることにしました。
Migration Runners · schambers/fluentmigrator Wiki · GitHub

 
コマンドプロンプトを起動し、以下を実行します。

"D:\GitHub\FluentMigrator-sample\packages\FluentMigrator.1.3.0.0\tools\Migrate.exe" /conn "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\GitHub\FluentMigrator-sample\sample.accdb" /provider jet /assembly "D:\GitHub\FluentMigrator-sample\FluentMigrator-sample\bin\Debug\FluentMigrator-sample.exe" /verbose true

なお、Migrate.exeやMS Access、今回作成したコンソールアプリケーションのパスは、環境に応じて変更します。

ログを見ると、Usersテーブルの他に、マイグレーション情報を格納するVersionInfoテーブルも作成されたようです。

-------------------------------------------------------------------------------
=============================== FluentMigrator ================================
-------------------------------------------------------------------------------
Source Code:
  http://github.com/schambers/fluentmigrator
Ask For Help:
  http://groups.google.com/group/fluentmigrator-google-group
-------------------------------------------------------------------------------
[+] Using Database jet and Connection String Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\GitHub\FluentMigrator-sample\sample.accdb
-------------------------------------------------------------------------------
VersionMigration migrating
-------------------------------------------------------------------------------
[+] Beginning Transaction
[+] CreateTable VersionInfo
CREATE TABLE [VersionInfo] ([Version] DECIMAL(20,0) NOT NULL)
=> 0.018001s
[+] Committing Transaction
[+] VersionMigration migrated
=> 0.0210012s
-------------------------------------------------------------------------------
VersionUniqueMigration migrating
-------------------------------------------------------------------------------
[+] Beginning Transaction
[+] CreateIndex VersionInfo (Version)
CREATE UNIQUE INDEX [UC_Version] ON [VersionInfo] ([Version] ASC)
=> 0.0030002s
[+] AlterTable VersionInfo
No SQL statement executed.
=> 0.001s
[+] CreateColumn VersionInfo AppliedOn DateTime
ALTER TABLE [VersionInfo] ADD COLUMN [AppliedOn] DATETIME
=> 0.0020002s
[+] Committing Transaction
[+] VersionUniqueMigration migrated
=> 0.0040003s
-------------------------------------------------------------------------------
VersionDescriptionMigration migrating
-------------------------------------------------------------------------------
[+] Beginning Transaction
[+] AlterTable VersionInfo
No SQL statement executed.
=> 0.0010001s
[+] CreateColumn VersionInfo Description String
ALTER TABLE [VersionInfo] ADD COLUMN [Description] TEXT
=> 0.0020002s
[+] Committing Transaction
[+] VersionDescriptionMigration migrated
=> 0.0040003s
-------------------------------------------------------------------------------
2014110601: Migration2014110601 migrating
-------------------------------------------------------------------------------
[+] Beginning Transaction
[+] CreateTable Users
CREATE TABLE [Users] ([ID] INTEGER NOT NULL, [Name] VARCHAR(255) NOT NULL, CONST
RAINT [PK_Users] PRIMARY KEY ([ID]))
=> 0.0040002s
INSERT INTO [VersionInfo] ([Version], [AppliedOn], [Description]) VALUES (201411
0601, '2014-11-05 20:55:16', 'Migration2014110601')
[+] Committing Transaction
[+] 2014110601: Migration2014110601 migrated
=> 0.0510029s
[+] Task completed.

 
MS Accessのテーブルを見ると、マイグレーションファイルの内容となっています。

f:id:thinkAmi:20141106062044p:plain

 
このことより、MS Access (*.accdb)であっても、Jetプロバイダを使えばマイグレーションができることが分かりました。

 

UsersテーブルのIDをオートナンバー型に変更

マイグレーションファイルMigration2014110602.csを作成します。

MS Accessのオートナンバー型にするには、Identity()メソッドを使えばよいようです。

using FluentMigrator;

namespace FluentMigrator_sample.Migrations
{
    [Migration(2014110602)]
    public class Migration2014110602 : Migration
    {
        public override void Up()
        {
            Alter.Table("Users")
                 .AlterColumn("ID").AsInt32().PrimaryKey().Identity();
        }

        public override void Down()
        {
            Alter.Table("Users")
                 .AlterColumn("ID").AsInt32().PrimaryKey();
        }
    }
}

 

マイグレーションの実行

No.1と同じコマンドを実行します。ログは以下の通りです。

-------------------------------------------------------------------------------
=============================== FluentMigrator ================================
-------------------------------------------------------------------------------
Source Code:
  http://github.com/schambers/fluentmigrator
Ask For Help:
  http://groups.google.com/group/fluentmigrator-google-group
-------------------------------------------------------------------------------
[+] Using Database jet and Connection String Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\GitHub\FluentMigrator-sample\sample.accdb
-------------------------------------------------------------------------------
2014110602: Migration2014110602 migrating
-------------------------------------------------------------------------------
[+] Beginning Transaction
[+] AlterTable Users
No SQL statement executed.
=> 0.001s
[+] AlterColumn Users ID Int32
ALTER TABLE [Users] ALTER COLUMN [ID] COUNTER NOT NULL
=> 0.0130008s
INSERT INTO [VersionInfo] ([Version], [AppliedOn], [Description]) VALUES (201411
0602, '2014-11-05 20:59:22', 'Migration2014110602')
[+] Committing Transaction
[+] 2014110602: Migration2014110602 migrated
=> 0.0290017s
[+] Task completed.

 
実際のテーブルのID列もオートナンバー型になっています。

f:id:thinkAmi:20141106062118p:plain

 

UsersテーブルにDescription(メモ型)を追加

さらに、マイグレーションファイルMigration2014110603.csを作成して、メモ型の列を追加してみます。

MS Accessではテキスト型のフィールドサイズが255までなので、それより長いサイズをAsString()メソッドに渡すと、メモ型になるようです。

using FluentMigrator;

namespace FluentMigrator_sample.Migrations
{
    [Migration(2014110603)]
    public class Migration2014110603 : Migration
    {
        public override void Up()
        {
            Alter.Table("Users")
                 .AddColumn("Description").AsString(256);
        }

        public override void Down()
        {
            Delete.Column("Description").FromTable("Users");
        }
    }
}

 

マイグレーションの実行

No.1と同じコマンドを実行し、ログを確認します。

-------------------------------------------------------------------------------
=============================== FluentMigrator ================================
-------------------------------------------------------------------------------
Source Code:
  http://github.com/schambers/fluentmigrator
Ask For Help:
  http://groups.google.com/group/fluentmigrator-google-group
-------------------------------------------------------------------------------
[+] Using Database jet and Connection String Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\GitHub\FluentMigrator-sample\sample.accdb
-------------------------------------------------------------------------------
2014110603: Migration2014110603 migrating
-------------------------------------------------------------------------------
[+] Beginning Transaction
[+] AlterTable Users
No SQL statement executed.
=> 0.0020001s
[+] CreateColumn Users Description String
ALTER TABLE [Users] ADD COLUMN [Description] TEXT NOT NULL
=> 0.0100005s
INSERT INTO [VersionInfo] ([Version], [AppliedOn], [Description]) VALUES (201411
0603, '2014-11-05 21:03:21', 'Migration2014110603')
[+] Committing Transaction
[+] 2014110603: Migration2014110603 migrated
=> 0.0290016s
[+] Task completed.

 
実際のテーブルにもDescription列が追加されています。

f:id:thinkAmi:20141106062130p:plain

ここで、VersionInfoテーブルを見てみると、以下の通り3行が存在します。

f:id:thinkAmi:20141106062136p:plain

 

マイグレーションロールバック

試しにロールバックしてみます。

コマンドの最後に /task rollbackオプションを追加して実行します。

"D:\GitHub\FluentMigrator-sample\packages\FluentMigrator.1.3.0.0\tools\Migrate.exe" /conn "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\GitHub\FluentMigrator-sample\sample.accdb" /provider jet /assembly "D:\GitHub\FluentMigrator-sample\FluentMigrator-sample\bin\Debug\FluentMigrator-sample.exe" /verbose true /task rollback

 
ログを見ると、No.3からNo.2の状態に戻っています。画像は省略しますが、実際のテーブルも同様でした。

-------------------------------------------------------------------------------
=============================== FluentMigrator ================================
-------------------------------------------------------------------------------
Source Code:
  http://github.com/schambers/fluentmigrator
Ask For Help:
  http://groups.google.com/group/fluentmigrator-google-group
-------------------------------------------------------------------------------
[+] Using Database jet and Connection String Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\GitHub\FluentMigrator-sample\sample.accdb
-------------------------------------------------------------------------------
2014110603: Migration2014110603 reverting
-------------------------------------------------------------------------------
[+] Beginning Transaction
[+] DeleteColumn Users Description
ALTER TABLE [Users] DROP COLUMN [Description]
=> 0.0060003s
DELETE FROM [VersionInfo] WHERE [Version] = 2014110603
[+] Committing Transaction
[+] 2014110603: Migration2014110603 reverted
=> 0.0230013s
[+] Task completed.

 
また、VersionInfoテーブルを見ると、No.3の行が削除されています。

f:id:thinkAmi:20141106062147p:plain

 
以上のようにFluentMigratorを使ってみましたが、なかなかよさそうでした。

あとはこれらのマイグレーションファイルをGitなどでバージョン管理をすれば、「なぜこのテーブルやカラムがあるのか?」という理由も残せるので安心です。

 

ソースコード

GitHubに上げました。
thinkAmi/FluentMigrator-sample