Microsoft.EntityFrameworkCore.Toolsでマイグレーションファイルをつくる時に、プロジェクトごとでEntityFrameworkCoreのバージョンを変えたかったので、その方法についてです。
その他dbの場所指定についてつまづいた部分です。
これによりバージョンを固定することで、プロジェクトごとであったり開発者間でもマイグレーションでの不具合を防ぐようにできました。
基本的には以下の内容になります。
マイグレーション時はパスがダメ
IDesignTimeDbContextFactoryをつくる
dotnet dotnet-ef migrations add InitialCreate --context FileDbContext
Build started...
Build succeeded.
Unable to create a 'DbContext' of type 'FileDbContext'. The exception 'Operation is not valid due to the current state of the object.' was thrown while attempting to create an instance. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
環境
Windows11
VSCode
.NET10
wpf
Microsoft.EntityFrameworkCore.Tools Ver10.0.7
EntityFrameworkCoreのマイグレーション
これまではglobalに入れて使っていましたが、プロジェクトでバージョンを分けたい場合の方法となります。
ツールマニフェスト作成
-
dotnet new tool-manifest
プロジェクト直下にdotnet-tools.jsonというマニフェストファイルが作成されます。
(空のテンプレート) -
dotnet tool install dotnet-ef --version 10.0.7
プロジェクトで使用しているEFCoreのバージョンと合わせて追加します。
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "10.0.7",
"commands": [
"dotnet-ef"
],
"rollForward": false
}
}
}
-
globalの場合は不要ですがこの場合はDesignが必要になるので追加します
dotnet add package Microsoft.EntityFrameworkCore.Design -
指定コマンド(dotnet-ef)を使えば指定バージョンが使用されます
dotnet dotnet-ef migrations add InitialCreate -
指定バージョンであることが確認できます
dotnet dotnet-ef
_/\__
---==/ \\
___ ___ |. \|\
| __|| __| | ) \\\
| _| | _| \_/ | //|\\
|___||_| / \\\/\\
Entity Framework Core .NET Command-line Tools 10.0.7
これでcsprojのバージョンとそろえることができました。
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.7">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.7">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
パスでエラー
wpfですがmsixにする予定なので、sqliteの保存場所にApplicationData.Current.LocalFolder.Pathを使用しています。
これは実行環境でないと空になりマイグレーションでエラーになるようです。
IDesignTimeDbContextFactoryを作ることで問題なく実行できました。
ApplicationData.Current.LocalFolderは、MSIXの実行時に初期化されるので、dotnet-ef実行時はアプリが起動していないのでnullになります。
ただ開発時とMSIXでdbの場所を分ける構成にしたため、
デザイン時専用のIDesignTimeDbContextFactoryが不要になりました。
MSIXのみdbパスを変える
これでMSIXのみApplicationData.Current.LocalFolder.Pathを使いますが、開発時は不要なので分けるようにしています。
| 実行形態 | 保存先の種類 | 実際のパス例 |
|---|---|---|
| VSCodeデバッグ | プロジェクトフォルダ直下 | project\devdb\files.db |
| exe実行 | exeのあるフォルダ | project\bin\Release\net10.0-windows10.0.19041.0\publish\devdb\files.db |
| MSIX | MSIXのsandbox内のLocalState | C:\Users<User>\AppData\Local\Packages<YourAppPackageID>\LocalState\files.db |
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
string folder;
if (IsRunningAsMsix())
{
// MSIXの場合
folder = ApplicationData.Current.LocalFolder.Path;
}
else
{
// 開発時
folder = Path.Combine(Environment.CurrentDirectory, "devdb");
}
Directory.CreateDirectory(folder);
var dbPath = Path.Combine(folder, "files.db");
options.UseSqlite($"Data Source={dbPath}");
}
private static bool IsRunningAsMsix()
{
try
{
var _ = Windows.ApplicationModel.Package.Current;
return true;
}
catch
{
return false;
}
}