SQL Server の FILESTREAM はバイナリデータを管理するのに便利な仕組みですが、Entity Framework の Code First ではまだサポートされていません(2019年2月現在)。
たとえば Entity Framework Core では、次の手順で FILESTREAM データにアクセスできるようになります。
1. インスタンスレベルで FILESTREAM を有効化します。
FILESTREAM の有効化と構成 | Microsoft Docs
2. FILESTREAM を有効化したデータベースを作成します。
FILESTREAM が有効なデータベースを作成する方法 | Microsoft Docs
3. モデルクラスに byte 配列型でプロパティを定義します。
public class FooTable
{
// :
public byte[] FileDataColumn { get; set; }
// :
}
4. 初期マイグレーションを作成します。
[パッケージマネージャーコンソールの場合]
Add-Migration <migration name> -Context SampleContext
[CLI コマンドの場合]
dotnet ef migrations add <migration name> --context SampleContext
5. Migrations フォルダ内にヘルパークラスを作成します。
UpTableAfter
メソッドでは、CREATE TABLE
の後処理として、FILESTREAM に必要な Id 列と制約を定義し、バイナリ列を再作成します。
DownTableBefore
メソッドでは、DROP TABLE
の前処理として、バイナリ列と制約を削除します。
public static class FileStreamMigration
{
public static void UpTableAfter(MigrationBuilder migrationBuilder, string tableName, string fileDataColumnName)
{
migrationBuilder.Sql($"ALTER TABLE [{tableName}] ADD [FsId] uniqueidentifier rowguidcol NOT NULL");
migrationBuilder.Sql($"ALTER TABLE [{tableName}] ADD CONSTRAINT [UQ_{tableName}_FsId] UNIQUE NONCLUSTERED ([FsId])");
migrationBuilder.Sql($"ALTER TABLE [{tableName}] ADD CONSTRAINT [DF_{tableName}_FsId] DEFAULT (NewID()) FOR [FsId]");
migrationBuilder.Sql($"ALTER TABLE [{tableName}] DROP COLUMN [{fileDataColumnName}]");
migrationBuilder.Sql($"ALTER TABLE [{tableName}] ADD [{fileDataColumnName}] varbinary(max) FILESTREAM NULL");
}
public static void DownTableBefore(MigrationBuilder migrationBuilder, string tableName, string fileDataColumnName)
{
migrationBuilder.Sql($"ALTER TABLE [{tableName}] DROP COLUMN [{fileDataColumnName}]");
migrationBuilder.Sql($"ALTER TABLE [{tableName}] DROP CONSTRAINT [DF_{tableName}_FsId]");
migrationBuilder.Sql($"ALTER TABLE [{tableName}] DROP CONSTRAINT [UQ_{tableName}_FsId]");
migrationBuilder.Sql($"ALTER TABLE [{tableName}] DROP COLUMN [FsId]");
}
}
6. 初期マイグレーションクラスの Up メソッド末尾にヘルパーメソッド呼び出しを追記します。
public partial class Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
:
migrationBuilder.CreateTable(
name: "FooTable", ...
:
FileStreamMigration.UpTableAfter(migrationBuilder, nameof(FooTable), nameof(FooTable.FileDataColumn));
}
7. 初期マイグレーションクラスの Down メソッド先頭にヘルパーメソッドを呼び出しを追記します。
protected override void Down(MigrationBuilder migrationBuilder)
{
FileStreamMigration.DownTableBefore(migrationBuilder, nameof(FooTable), nameof(FooTable.FileDataColumn));
:
migrationBuilder.DropTable(
name: "FooTable");
:
これで byte 配列を介した Transact-SQL による FILESTREAM アクセス が実現できます。
Ignore 方式(検討を推奨)
ファイルサイズに対してよりスケーラブルな 「ファイル システム ストリーミング」(Win32 API)方式 でアクセスする場合や、モデルとは別個にバイナリデータを取得したい場合は、以下のようにします。
-
DbContext
クラスのOnModelCreating
メソッドでファイルデータ列をIgnore
する。 -
FileStreamMigration.UpTableAfter
メソッドからDROP COLUMN
のステートメントを除去する。 - バイナリデータ列値の取得(
SELECT
)、保存(UPDATE
)ロジックを別途実装する。