リバース エンジニアリング

リバース エンジニアリングは、データベース スキーマに基づいてエンティティ型クラスおよび DbContext クラスをスキャフォールディングするプロセスです。 これは、EF Core パッケージ マネージャー コンソール (PMC) ツールの Scaffold-DbContext コマンド、または .NET コマンド ライン インターフェイス (CLI) ツールの dotnet ef dbcontext scaffold コマンドを使用して実行できます。

前提条件

  • リバース エンジニアリングを行う前に、PMC ツール (Visual Studio のみ) または CLI ツールのいずれかをインストールする必要があります。 詳細については、リンクを参照してください。
  • スキャフォールディングするプロジェクトにNuGet Microsoft.EntityFrameworkCore.Design パッケージをインストールします。
  • また、リバース エンジニアリングするデータベース スキーマに対して適切なデータベース プロバイダーをインストールする必要もあります。

接続文字列

コマンドの最初の引数は、データベースへの接続文字列です。 ツールでは、この接続文字列を使用してデータベース スキーマを読み取ります。

接続文字列の引用符とエスケープ方法は、コマンドの実行に使用しているシェルによって異なります。 詳細については、シェルのドキュメントを参照してください。 たとえば、PowerShell では $ 文字をエスケープする必要がありますが、\ については不要です。

dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer

構成とユーザー シークレット

ASP.NET Core プロジェクトがある場合は、Name=<connection-string> 構文を使用して構成から接続文字列を読み取ることができます。

これはシークレット マネージャー ツールと一緒に使用して、データベースのパスワードをコードベースとは別に保持するのに適しています。

dotnet user-secrets set ConnectionStrings:Chinook "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook"
dotnet ef dbcontext scaffold Name=ConnectionStrings:Chinook Microsoft.EntityFrameworkCore.SqlServer

プロバイダー名

2 番目の引数はプロバイダー名です。 プロバイダー名は通常、プロバイダーの NuGet パッケージ名と同じです。

テーブルの指定

データベース スキーマ内のすべてのテーブルは、既定でエンティティ型にリバース エンジニアリングされます。 スキーマとテーブルを指定することにより、リバース エンジニアリングされるテーブルを制限できます。

--schema オプションを使用すると、スキーマ内のすべてのテーブルを含めることができますが、--table を使用して、特定のテーブルを含めることができます。

複数のテーブルを含めるには、オプションを複数回指定します。

dotnet ef dbcontext scaffold ... --table Artist --table Album

名前の保持

既定では、型およびプロパティについての .NET の名前付け規則に適切に一致するよう、テーブル名と列名が固定されています。 PMC -UseDatabaseNames でスイッチを指定するか .NET Core CLI で --use-database-names オプションを指定すると、この動作が無効になり、元のデータベース名を可能な限り保持するようになります。 無効な .NET 識別子は引き続き固定され、ナビゲーション プロパティのような合成された名前は .NET の名前付け規則に準拠したままになります。

Fluent API またはデータの注釈

エンティティ型は、既定では Fluent API を使用して構成されます。 可能な場合に代わりにデータ注釈を使用するには、-DataAnnotations (PMC) または --data-annotations (.NET Core CLI) を指定します。

たとえば、Fluent API を使用すると、次のようにスキャフォールディングされます。

entity.Property(e => e.Title)
    .IsRequired()
    .HasMaxLength(160);

データ注釈を使用すると、次のようにスキャフォールディングされます。

[Required]
[StringLength(160)]
public string Title { get; set; }

DbContext 名

スキャフォールディングされた DbContext クラス名は、既定ではデータベースの名前に Context がサフィックスとして付けられます。 別のものを指定するには、PMC では -Context を使用し、.NET Core CLI では --context を使用します。

ディレクトリと名前空間

エンティティ クラスと DbContext クラスは、プロジェクトのルート ディレクトリにスキャフォールディングされ、プロジェクトの既定の名前空間が使用されます。

--output-dir を使用して、クラスがスキャフォールディングされるディレクトリを指定することができます。また、--context-dir を使用して、エンティティ型クラスとは別のディレクトリに DbContext クラスをスキャフォールディングすることができます。

dotnet ef dbcontext scaffold ... --context-dir Data --output-dir Models

既定では、名前空間はルート名前空間に、プロジェクトのルート ディレクトリの下にあるサブディレクトリの名前を加えたものになります。 ただし、EFCore 5.0 以降では、--namespace を使用して、すべての出力クラスの名前空間をオーバーライドできます。 また、--context-namespace を使用して、DbContext クラスの名前空間のみをオーバーライドすることもできます。

dotnet ef dbcontext scaffold ... --namespace Your.Namespace --context-namespace Your.DbContext.Namespace

しくみ

リバース エンジニアリングは、データベース スキーマを読み取ることによって開始されます。 テーブル、列、制約、およびインデックスに関する情報が読み取られます。

次に、スキーマ情報を使用して EF Core モデルを作成します。 テーブルを使用してエンティティ型を作成し、列を使用してプロパティを作成し、外部キーを使用してリレーションシップを作成します。

最後に、モデルを使用してコードを生成します。 対応するエンティティ型クラス、Fluent API、およびデータ注釈は、アプリから同じモデルを再作成するためにスキャフォールディングされます。

制限事項

  • モデルに関するすべての情報を、データベース スキーマを使用して表すことはできません。 たとえば、継承階層所有型、およびテーブル分割に関する情報は、データベース スキーマには存在しません。 このため、これらの構造はリバース エンジニアリングされません。
  • また、一部の列の型 は EF Core プロバイダーでサポートされない場合があります。 これらの列はモデルに含まれません。
  • EF Core モデルで同時実行トークンを定義して、2 人のユーザーが同時に同じエンティティを更新できないようにすることができます。 一部のデータベースには、この型の列を表す特殊な型 (SQL Server での rowversion など) があり、この場合はこの情報をリバース エンジニアリングできます。ただし、その他の同時実行トークンはリバース エンジニアリングされません。
  • EF Core 6 より前では、 C# 8 null 許容参照型機能 はリバース エンジニアリングではサポートされていませんでした。EF Core では、この機能が無効であると想定した C# コードが常に生成されました。 たとえば、null 許容テキスト列は、プロパティが必要かどうかを構成するために使用される Fluent API またはデータ注釈を使用して、型stringではなくstring?プロパティとしてスキャフォールディングされました。 以前のバージョンの EF Core を使用している場合でも、スキャフォールディングされたコードを編集し、これらを C# の null 許容注釈に置き換えることができます。

モデルのカスタマイズ

EF Core によって生成されるコードはユーザーのコードです。 自由に変更して構いません。 同じモデルを再びリバース エンジニアリングする場合のみ再生成されます。 スキャフォールディングされたコードは、データベースへのアクセスに使用できる "1 つ" のモデルを表しますが、使用できる "唯一" のモデルではありません。

エンティティ型クラスと DbContext クラスをニーズに合わせてカスタマイズします。 たとえば、型とプロパティの名前を変更したり、継承階層を導入したり、テーブルを複数のエンティティに分割したりすることができます。 また、一意でないインデックス、未使用のシーケンスとナビゲーション プロパティ、オプションのスカラー プロパティ、および制約名をモデルから削除することもできます。

さらに、コンストラクター、メソッド、プロパティなどを、 別個のファイルで別の部分クラスを使用して追加することもできます。 この方法は、モデルを再びリバース エンジニアリングする場合でもうまく機能します。

モデルの更新

データベースに変更を加えた後、その変更を反映するために EF Core モデルを更新することが必要になる場合があります。 データベースの変更が単純な場合は、EF Core モデルに単純に手動で変更を加えるのが最も簡単かもしれません。 たとえば、テーブルまたは列の名前を変更したり、列を削除したり、列の型を更新したりすることは、コードに行う些細な変更です。

ただし、大幅な変更は、手動で行えるほど簡単ではありません。 よくあるワークフローの 1 つとして、-Force (PMC) または --force (CLI) を使用してデータベースからモデルを再度リバース エンジニアリングし、既存のモデルを更新されたモデルで上書きすることがあります。

よく要求されるもう 1 つの機能は、名前変更、型階層などのカスタマイズを維持しながら、データベースからモデルを更新する機能です。この機能の状況を追跡するには、問題 #831 を使用します。

警告

データベースからモデルを再度リバース エンジニアリングすると、ファイルに加えた変更はすべて失われます。

ヒント

Visual Studio を使用する場合、EF Core コマンド ライン ツールの上に構築されたグラフィカル ツールである EF Core のパワー ツール コミュニティ拡張機能には、追加のワークフローとカスタマイズのオプションが用意されています。