Entity Framework 6 で開発環境以外から ef6.exe を使ってマイグレーションを適用する

Entity Framework 6 で開発環境以外から ef6.exe を使ってマイグレーションを適用する

最近では Entity Framework 6 を使って新しく開発することはないと思いますが、既存アプリの改修ではまだ利用せざるを得ないこともあり、データベースを変更するときにはマイグレーションが必要になります。

ただ Entity Framework のマイグレーションは昔からわかりにくく、特に開発環境 以外 から適用するときは毎回けっこう調べ直す必要があります。

今回は 2020年12月時点で Entity Framework 6.4 のデータベースマイグレーションを行う方法を紹介します。なお、この記事にはマイグレーションファイル自体を作る手順はありません。

概要

前述のとおり、開発環境 (Visual Studio) であれば パッケージマネージャーコンソールから PowerShell コマンドの Update-Database を叩けば、マイグレーションを実行させることができます。

ただ、当然ながら運用環境には Update-Database などというコマンドは存在しませんので、別の手段で運用中のデータベースにマイグレーションを適用する必要があります。

運用環境でマイグレーションを実行するには EF6 のパッケージに同梱されている ef6.exe を使用します。

ちなみに昔は migrate.exe でした。驚くことに MS Docs には未だに migrate.exe の記述しかありません。にもかかわらず EF 6.4.4 には migrate.exe はもう同梱されていないので全く使えない手順になっています。

ef6.exe のありか

まず ef6.exe がどこにあるか、ですが、おそらく下記のフォルダにあります。

<ソリューションかプロジェクトのパス>\packages\EntityFramework.<バージョン>\tools\net45\win-x86

tools フォルダ配下は下記のような構成になっており、 .NET Framework 4.0 向けと .NET Framework 4.5 向け、さらに any ビルドと x86 ビルドがあります。環境に応じたものを使用します。

entity framework 6 apply migrations to database with ef6exe 1

ef6.exe の使い方

配置

マイグレーションを含むプロジェクトでビルドしたバイナリー (*.dll か *.exe) と同じフォルダに ef6.exe を配置します。

*.dll や .exe の**アプリケーション構成ファイル (.config) も同じフォルダー**にあることを確認します。たとえば HogeHoge プロジェクトの場合は下記のような構成になります。

  • ef6.exe
  • HogeHoge.dll
  • HogeHoge.dll.config
  • その他必要なファイル群

構成ファイル (*.config) には Entity Framework の接続情報が定義されていることを確認しましょう。

構成ファイル内の接続文字列の例 (SQLite の場合)

<connectionStrings>
  <add name="hogehoge" connectionString="Data Source=C:\hogehoge\db.sqlite;" providerName="System.Data.SQLite.EF6"/>
</connectionStrings>

コマンドラインでの使い方

前述のとおり正式な Microsoft Docs は存在しないため、下記の Issue コメントが一番の情報源という心もとない話です。

とはいえコマンド内のヘルプが割と充実しているので、ドキュメントがなくても使うことはできます。順番に見ていきましょう。

ef6.exe を配置したフォルダーで PowerShell を開いて実行していきます(コマンドプロンプトでも bash でも OK ですが PowerShell が一番無難と思います) 。

まずは --help を叩くと第一段階のヘルプが表示されます。

> .\ef6.exe --help
Entity Framework Command-line Tools 6.4.4

Usage: ef6 [options] [command]

Options:
  --version        Show version information
  -h|--help        Show help information
  -v|--verbose     Show verbose output.
  --no-color       Don't colorize output.
  --prefix-output  Prefix output with level.

Commands:
  database    Commands to manage the database.
  migrations  Commands to manage migrations.

Use "ef6 [command] --help" for more information about a command.

コマンドに databasemigrations があることがわかります。

migrations コマンド

先に migrations コマンドの方から見ていきましょう。 migrations--help をつけて実行するともう1段下のヘルプが参照できます。

> .\ef6.exe migrations --help

Usage: ef6 migrations [options] [command]

Options:
  -h|--help        Show help information
  -v|--verbose     Show verbose output.
  --no-color       Don't colorize output.
  --prefix-output  Prefix output with level.

Commands:
  add     Scaffolds a migration script for any pending model changes.
  enable  Enables Code First Migrations in a project.
  list    Displays the migrations that have been applied to the target database.

add, enable, list の3つのサブコマンドが存在します。それぞれそれぞれ Visual Studio (パッケージマネージャーコンソール)における Add-MigrationEnable-Migrations, Get-Migrations に相当します。

addenable は通常開発環境上で実行するほうが便利でしょうから割愛します。

list を叩いてみるとすでに適用されているマイグレーションの一覧が得られます。 --assembly オプションと --config オプションを指定して呼び出します。

> .\ef6.exe migrations list --assembly ".\HogeHoge.dll" --config ".\HogeHoge.dll.config"
Retrieving migrations that have been applied to the target database.
202001230938422_Initial

未適用のマイグレーション一覧を見る方法はないようです。

database コマンド

database コマンドはその名のとおりデータベースに対して実行するコマンドです。

こちらのサブコマンドは update しかありません。これが Update-Database と同じようにデータベースにマイグレーションを実行するためのコマンドです。

update の詳細なヘルプを見てみます。

> .\ef6.exe database update --help

Usage: ef6 database update [options]

Options:
  --source <MIGRATION>             Only valid with --script. Specifies the name of a particular migration to use as the update's starting point. If omitted, the last applied migration in the database will be used.
  --target <MIGRATION>             Specifies the name of a particular migration to update the database to. If omitted, the current model will be used.
  --script                         Generate a SQL script rather than executing the pending changes directly.
  -f|--force                       Specifies that data loss is acceptable during automatic migration of the database.
  --migrations-config <TYPE>       Specifies the migrations configuration to use. If omitted, migrations will attempt to locate a single migrations configuration type in the target project.
  -a|--assembly <PATH>             The assembly to use.
  --project-dir <PATH>             The project directory. Defaults to the current directory.
  --language <LANGUAGE>            The language. Defaults to 'C#'.
  --root-namespace <NAMESPACE>     The root namespace. Defaults to the target assembly name.
  --data-dir <PATH>                The data directory.
  --config <PATH>                  Specifies the configuration file to use for named connection strings.
  --connection-string-name <NAME>  Specifies the name of a connection string to use from the application's configuration file.
  --connection-string <STRING>     Specifies the connection string to use. If omitted, the context's default connection will be used.
  --connection-provider <NAME>     Specifies the provider invariant name of the connection string.
  -h|--help                        Show help information
  -v|--verbose                     Show verbose output.
  --no-color                       Don't colorize output.
  --prefix-output                  Prefix output with level.

オプションはほぼ migrations list と同様です。

データベースへのマイグレーションの適用

ということでデータベースに対してマイグレーションを適用するには下記のように --assembly オプションと --config オプションをつけて実行します。

> .\ef6.exe database update -v --assembly ".\HogeHoge.dll" --config ".\HogeHoge.dll.config"

Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Target database is: 'main' (DataSource: , Provider: System.Data.SQLite, Origin: Configuration).
Applying explicit migrations: [202011240318455_AddAdditionalTables].
Applying explicit migration: 202011240318455_AddAdditionalTables.
CREATE TABLE "AdditionalTable" (
~中略~
;

Running Seed method.

なお -v (--verbose) オプションをつけておくと実際に実行される SQL まで確認できますので安心 (?) ですね。

マイグレーションのロールバック (Revert migrations)

せっかくのマイグレーション機能なので、巻き戻したいこともあるでしょう。ロールバックしたいときは --target オプションを指定します。

--target オプション 機能
0 マイグレーションが何も適用されていない状態に戻す
<数値> 指定したインデックスのマイグレーションまで適用されている状態に戻す
"<マイグレーション名>" 指定したマイグレーション名のマイグレーションまで適用されている状態に戻す

※基本的には Update-Database-TargetMigration オプションと同じです。

つまり、 A, B, C, D, E のマイグレーションがあり、 E まで適用済みとして、 C に戻したい場合は、 --target"C" もしくは 3 を指定します。

.\ef6.exe database update -v --assembly ".\HogeHoge.dll" --config ".\HogeHoge.dll.config" --target "C"

また、 A も適用されていない状態に戻す場合は 0 を指定します。

.\ef6.exe database update -v --assembly ".\HogeHoge.dll" --config ".\HogeHoge.dll.config" --target 0

ただ、私の環境では SQLite のライブラリにバグがあるのか、生成された SQL (DROP INDEX) が syntax error になって戻せませんでした(笑)

SQL Server などではきっとうまくいくでしょう!

まとめ

長くなりましたが、結論として Entity Framework 6.4 で ef6.exe を使ってマイグレーションを適用するには下記のように ef6.exe database update を実行します。

.\ef6.exe database update -v --assembly ".\HogeHoge.dll" --config ".\HogeHoge.dll.config"

データベースのバックアップをとっておくことをお忘れなく。

kenzauros