Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Stop repeating dotnet ef flags: repository-level defaults with dotnet-ef.json

2026年09月30日に「Dev.to」が公開したITニュース「Stop repeating dotnet ef flags: repository-level defaults with dotnet-ef.json」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

EF Core 11から、`dotnet ef`コマンドで毎回指定していた`--project`などの引数を`.config/dotnet-ef.json`に記述し、デフォルト設定できるようになった。これによりコマンドが簡潔になり、引数忘れによるプロジェクト指定ミスを防げる。設定はリポジトリで一元管理でき、コマンドライン引数は設定より優先される。

ITニュース解説

dotnet efコマンドは、Entity Framework Coreというデータアクセス技術を使う上で非常に重要なツールだ。システムエンジニアを目指す初心者にとって、データベースとの連携は避けて通れないテーマであり、EF CoreはC#で書かれたアプリケーションとデータベースを効率的に連携させるための強力な手段を提供する。dotnet efコマンドはそのEF Coreが提供する機能、特に「マイグレーション」と呼ばれるデータベーススキーマの変更管理や、データベースからコードを生成する「リバースエンジニアリング」といった操作を行う際に利用される。

これまで、このdotnet efコマンドを使用する際には、アプリケーションの構造が複雑になるにつれて、繰り返し多くのオプションを指定する必要があった。特に、複数のプロジェクトで構成されるソリューションでは、--project、--startup-project、--framework、--contextといったオプションを毎回コマンドラインに記述しなければならなかった。

例えば、Web APIプロジェクト(App.Api)と、データベースアクセスロジックを含むインフラストラクチャプロジェクト(App.Infrastructure)のように、役割が異なる複数のプロジェクトで構成されている場合を想像してみよう。データベースの変更(マイグレーション)は通常、インフラストラクチャプロジェクトで行われるが、dotnet efツールが動作するには、アプリケーションの起動プロジェクト(Web APIプロジェクトなど)を通じてデータベース接続情報やモデル構成を読み込む必要がある。このため、--projectでマイグレーションの対象となるインフラストラクチャプロジェクトを、--startup-projectで起動プロジェクトを指定する必要があり、これらは常に異なるプロジェクトになることが多かった。

このような状況では、「データベースに新しいテーブルを追加するマイグレーションを作成する」という簡単な操作でも、dotnet ef migrations add AddOrders --project src/App.Infrastructure --startup-project src/App.Api --framework net11.0 --context AppDbContextのように、非常に長く複雑なコマンドを打たなければならなかった。この長いコマンドは、READMEファイル、シェルスクリプト、CI/CDパイプライン、統合開発環境(IDE)の設定など、様々な場所にコピーされて存在することになる。

しかし、これらのオプションが複数箇所に分散していると、情報の「ずれ」が発生しやすくなる。例えば、ある場所では--projectオプションを省略してしまい、コマンドを実行したカレントディレクトリにあるプロジェクト(例えばWeb APIプロジェクト)に誤ってマイグレーションファイルが作成されてしまう、といった問題が頻繁に起こっていた。また、開発環境、CI/CD環境、本番環境で異なる引数セットでツールが呼び出されると、同じコマンドでも異なるターゲットを操作してしまう可能性があり、予期せぬ不具合や手戻りが発生する原因となっていた。これは開発者の生産性を低下させ、システムの信頼性にも影響を及ぼす深刻な問題だったのだ。

このような繰り返し行われるオプション指定の手間と、それに伴う潜在的な問題を解決するため、EF Core 11以降で新しい機能が導入された。それが、.config/dotnet-ef.jsonファイルを利用したリポジトリレベルのデフォルトオプション設定機能である。

この機能の核心は、dotnet efコマンドが実行される際に、カレントディレクトリから親ディレクトリへと順に.config/dotnet-ef.jsonというファイルを探し、最初に見つかったファイルからデフォルトのオプション値を読み込むという点にある。これにより、プロジェクトのリポジトリルートにこのファイルを一つ配置しておけば、そのリポジトリ内のどのディレクトリからdotnet efコマンドを実行しても、同じデフォルト設定が適用されるようになる。コマンドラインで特定のオプションが省略された場合、このファイルに定義された値が自動的に適用されるため、前述した長いコマンドを毎回記述する必要がなくなるのだ。

このファイルの発見方法にはルールがある。dotnet efコマンドが実行されると、まずカレントディレクトリから.configというサブディレクトリを探し、その中にdotnet-ef.jsonがあるかを確認する。見つからなければ、一つ上の親ディレクトリに移り、再度同じように探す。このプロセスを繰り返して、最初に見つかったファイルのみが使用される。したがって、リポジトリのルートにファイルを置けば、リポジトリ全体に設定が適用され、特定のサブディレクトリに別のファイルを置けば、そのサブディレクトリ以下のコマンドにはそちらの設定が優先されるという仕組みになっている。

オプション値の適用には明確な優先順位がある。最も優先されるのは、コマンドラインで直接指定されたオプションだ。例えば、.config/dotnet-ef.jsonで--configuration Debugが設定されていても、コマンドラインでdotnet ef migrations add AddOrders --configuration Releaseと指定すれば、Releaseが優先される。次に優先されるのが、.config/dotnet-ef.jsonで指定された値である。そして、どちらも指定されていない場合は、dotnet efツールに元々組み込まれているデフォルト値が使用される。このように、明示的に指定された値が常に優先されるため、柔軟な運用が可能になる。

dotnet-ef.jsonファイル内でプロジェクトや起動プロジェクトのパスを指定する際には、絶対パスではなく、常に相対パスを使用することが推奨される。相対パスは、.configディレクトリを含むディレクトリ(通常はリポジトリのルート)を基準として解決される。例えば、リポジトリルートに.config/dotnet-ef.jsonがあり、その中に"project": "src/App.Infrastructure"と記述されていれば、dotnet efコマンドをリポジトリルートから実行しようと、src/App.Apiディレクトリから実行しようと、常にリポジトリルートのsrc/App.Infrastructureプロジェクトが対象となる。これにより、開発環境やCI/CD環境でのパスの差異による問題を回避できる。

設定ファイルはJSON形式で、project、startupProject、framework、configuration、context、runtime、verbose、noColor、prefixOutputといったプロパティを設定できる。文字列型のプロパティと真偽値(ブーリアン)型のプロパティがあり、誤った形式やサポートされていないプロパティが記述された場合はエラーとして報告されるため、設定ミスに気づきやすい。

この機能を使うことで、次のようにコマンドを劇的に簡素化できる。 リポジトリのルートディレクトリに.config/dotnet-ef.jsonファイルを作成し、例えば以下のように記述する。

1{
2  "project": "src/App.Infrastructure",
3  "startupProject": "src/App.Api",
4  "framework": "net11.0",
5  "configuration": "Debug",
6  "context": "AppDbContext"
7}

この設定ファイルがあれば、これまでは長かったコマンドが、単にdotnet ef migrations add AddOrdersと書くだけで済むようになる。この簡素化されたコマンドは、リポジトリのルートからでも、src/App.Apiディレクトリからでも、同じように正しく動作する。これにより、コマンドの可読性が向上し、記述ミスやコピペミスによる問題を大幅に削減できる。また、CI/CDスクリプトや開発者ごとの設定も統一され、チーム全体の生産性と整合性が向上する。

ただし、この便利な機能にもいくつかの考慮点や注意点がある。 一つは、暗黙的な動作が増えることだ。コマンドラインからは短く見えるコマンドでも、実際には設定ファイルから多くのオプションが補完されているため、その背景を知らないと混乱する可能性がある。開発者は.config/dotnet-ef.jsonファイルの存在とその内容を理解しておく必要がある。 また、スケーラビリティにも限界がある。.config/dotnet-ef.jsonファイルは一番近くのファイル一つだけが使用され、複数のデータベースコンテキスト(DbContext)や独立した複数のソリューションがあるリポジトリでは、一つのファイルで全ての状況に対応できない場合がある。そのような場合は、サブツリーごとにファイルを配置したり、特定のコマンドでは--contextオプションを明示的に指定したりする必要がある。この設定ファイルでカバーできるオプションは限られており、データベース接続文字列や特定の出力ディレクトリ、アプリケーションに転送する引数などは、引き続きコマンドラインで直接指定する必要がある。

特に注意すべきアンチパターンがいくつかある。 一つは、絶対パスをコミットしてしまうことだ。自分の環境で動作確認した際に解決された絶対パスをそのままファイルに記述してしまうと、他の開発者の環境やCI/CD環境ではそのパスが存在せず、コマンドが失敗する原因となる。常に.configディレクトリを含むディレクトリからの相対パスを使用するべきである。 次に、複数のDbContextが存在するリポジトリで、リポジトリ全体のデフォルト--contextを設定してしまうことだ。これにより、意図しないDbContextに対してコマンドが実行されてしまう可能性があるため、複数のDbContextを扱う場合はこのオプションをファイルに含めず、必要な時にコマンドラインで明示的に指定することを検討しよう。 また、verbose: trueやnoColor: trueといった出力に関する真偽値オプションを共有ファイルに設定することも注意が必要だ。これはチーム全員に適用され、コマンドラインでこれらの設定を無効にするオプションがないため、個人の好みに合わない場合でも変更できない。これらはチーム全体で合意が得られた場合にのみ設定するべきだ。 最後に、既存のラッパースクリプトなどに古いオプションが残ったままだと、コマンドラインのオプションが設定ファイルよりも優先されるため、設定ファイルの内容が反映されない場合がある。設定ファイルを導入したら、古い冗長なオプションは全て削除し、設定ファイルが唯一の情報源となるようにすることが重要だ。

この新機能を導入する際には、いくつかのチェックリストを活用しよう。まず、dotnet ef --versionコマンドで、インストールされているツールがEF Core 11以降のバージョンであることを確認し、必要であればdotnet tool update --global dotnet-efで更新する。次に、リポジトリのルートに.config/dotnet-ef.jsonファイルを作成し、チーム全体で共有したい最小限のプロパティを、リポジトリルートからの相対パスで記述してコミットする。その後、リポジトリルートからと、サブディレクトリからそれぞれdotnet ef dbcontext infoなどのコマンドを実行し、同じ対象プロジェクトが報告されることを確認して、設定が正しく適用されていることを検証する。さらに、--configuration Releaseのような明示的なオーバーライドオプションを使って、コマンドラインの値がファイルの設定よりも優先されることを確認する。最後に、意図的に不正な形式のファイルを試作ブランチで作成し、CLIがエラーを報告し、パイプラインが失敗するかどうかをテストして、エラーハンドリングの動作を確認しておくことも重要だ。そして、全ての既存スクリプトやドキュメントから、重複する--project、--startup-project、--framework、--contextなどのフラグを削除すれば、クリーンで効率的なdotnet efの利用環境が整うことになる。

この機能は、EF Coreを使った開発の生産性を向上させ、チーム開発における一貫性を確保するための非常に有用な改善点だ。システムエンジニアを目指す上では、このようなツールの改善や設定ファイルの活用方法を理解し、効率的な開発プラクティスを取り入れることが、これからのキャリアにおいて大きな強みとなるだろう。

関連コンテンツ

関連IT用語