Entity FrameworkコアにエンティティPOCOクラスを記述する適切な方法は何ですか?

.net asp.net-core c# entity-framework entity-framework-core

質問

EF Coreは、デフォルトでは「コード第1の考え方」を持っています。つまり、コードファーストの方法で使用されることになっています。データベースファーストのアプローチがサポートされていても、既存のデータベースをリバースエンジニアリングするだけであり、そのコードを最初に表現します。つまり、Scaffold-DbContextコマンドによるデータベースから生成されたコードで "手作業で"コード(コードファースト)で作成されたモデル(POCOクラス)は同一でなければなりません。

意外なことに、公式のEFコア文書は大きな違いを示しています。次に、コードでモデルを作成する例を示します。https : //ef.readthedocs.io/en/latest/platforms/aspnetcore/new-db.html次に、既存のデータベースからリバースエンジニアリングする例を示します。https: //ef.readthedocs.io/en/latest/platforms/aspnetcore/existing-db.html

これは最初のケースのエンティティクラスです:

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

これは第2の場合のエンティティクラスです:

public partial class Blog
{
    public Blog()
    {
        Post = new HashSet<Post>();
    }

    public int BlogId { get; set; }
    public string Url { get; set; }

    public virtual ICollection<Post> Post { get; set; }
}

最初の例は非常にシンプルで非常に明白なPOCOクラスです。これはドキュメントのどこにでも表示されます(データベースから生成されたサンプルを除く)。しかし、2番目の例では、いくつかの追加があります:

  • クラスは部分的に宣言されています(ただし、別の部分的な定義はありません)。
  • ナビゲーションプロパティはList <T>の代わりにICollection <T>です
  • ナビゲーションプロパティは、コンストラクタの新しいHashSet <T>()に初期化されます。このような初期化はコードの最初の例ではありません。
  • ナビゲーションプロパティは仮想として宣言されます
  • 生成されたコンテキストクラスのDbSetメンバも仮想です。

私はデータベースからモデルをスカッフォールディング(この記事の執筆時点では最新のツール)しようとしましたが、表示されているとおりにエンティティが生成されるため、これは古いドキュメントの問題ではありません。公式のツールでは異なるコードが生成され、公式のドキュメントでは、部分クラス、仮想メンバ、構造の初期化などをせずに、異なる(些細な)コードを書くことが提案されています。

私の質問は、コードでモデルを構築しようとすると、私はどのようにコードを書くべきですか?私はListの代わりにICollectionを使うのが好きですが、これは一般的ですが、それ以外には、私がドキュメントやMSツールに従う必要があるかどうか分からないのですか?それらを仮想として宣言する必要がありますか?コンストラクタで初期化する必要がありますか?等...

私は古いEF時代から、仮想ナビゲーションプロパティで遅延ロードを許可していることは分かっていますが、EFコアでは(まだ)サポートされていませんし、他の用途についてはわかりません。多分それはパフォーマンスに影響を与えますか?たぶんツールは、遅延保証が実装されるときに、POCOのクラスとコンテキストがそれをサポートできるように、将来保証されたコードを生成しようとしますか?もしそうなら、私は遅延ロードを必要としないのでそれらを取り除くことができますか?(すべてのデータクエリはリポジトリにカプセル化されています)

まもなく、なぜ違いがあるのか​​、コードでモデルを構築するときにどのスタイルを使用すべきかを理解してください。

受け入れられた回答

私はあなたが言及した各ポイントに短い答えを出そうとします

  • partialクラスは、ツール生成コードに特に便利です。モデルのみの派生プロパティを実装するとします。コードの場合は、まずどこでも好きなようにしてください。データベースを最初に更新する場合は、クラスファイルが書き直されます。したがって、拡張コードを保持したい場合は、それをマネージドモデル外の別のファイルに配置する必要があります。これは、 partial 、自動生成されたコードを手動で調整することなくクラスを拡張するのに役立ちます。

  • ICollectionは、コードであっても、間違いなく適切な選択ICollection 。あなたのデータベースは、ソートステートメントなしでは、おそらく定義された注文をサポートしないでしょう。

  • コンストラクタの初期化は、少なくとも便利です。空のコレクションがデータベースに似ているか、プロパティをまったく読み込まなかったとします。コンストラクタがなければ、コード内の任意の点で明示的にnullを処理する必要があります。 ListHashSetどちらを使うべきかは、今私が答えることができないものです。

  • virtualは、データベースエンティティのプロキシ作成を可能にします。これは、すでに述べたようにレイジーローディングとトラッキングを変更するという2つの点で役に立ちます。プロキシオブジェクトは、セッターで直ちに仮想プロパティの変更を追跡できますが、コンテキスト内の通常のオブジェクトはSaveChangesで検査する必要があります。場合によっては、これがより効率的になる場合があります(一般的ではありません)。

  • virtual IDbSetコンテキストエントリにより、単体テストのテストモックアップコンテキストの設計が容易になります。他のユースケースも存在する可能性があります。



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ