web-dev-qa-db-ja.com

Entity Framework Code First、C#クラス分離およびEAV

ASP.NET MVCアプリケーションの一部を再設計しているところです。現在、Entity Framework 6.1のコードファーストアプローチを使用しています。

私は最近それを読んでいます(私が間違っている場合は修正してください、DBについてはあまり知りません):結合は高価です。データベースを正規化し、できるだけ少ないクエリで実行する必要があります。 Entity Frameworkは、プロパティを「仮想化」してそれを取得しようとするたびに結合を行います(積極的/遅延読み込み)。非正規化が必要にならない限り、エンティティ属性値アプローチ(EAV)は避ける必要があります(正解)。

コードファーストのアプローチでは、C#OOPコード(POCO)を使用してDBスキーマを記述できます。つまり、OOPのSOLID原則(正しい))を遵守する必要があります最初の1つは単一の責任です。つまり、クラスは1つのことだけを実行する必要があります(ここでも、間違っている場合は修正してください)。

ここで問題が発生します(これが初めて発生します)。約30のプロパティを持つクラスがあります。対EAVで考える前に、それに応じてモデルを分離しました。

enter image description here

ご覧のとおり、List <>タイプのない多くの仮想プロパティがあるため、これは1対1の関係であることを意味します。以前のスタックオーバーフローの投稿で読んだのですが、1対1の関係は避けて、同じテーブルに配置することをお勧めします。もちろん、その1対1が他のテーブルから呼び出されない場合です。 EAVを防ぐため、Joinします。

SOLID=原則に従って、いくつかのプロパティを外部クラスに抽出しました。それらは独自のテーブルを取得します。

したがって、問題は、Entity Frameworkでモデリングする場合、OOPアプローチよりも完全に正規化された設計を優先すべきですか?

2
Jose A

(パーティーには遅れましたが、私は抵抗できませんでした)

誤解を正してみましょう。

結合は高価です

何と比べて?もちろん、1つのフラットテーブルを読み取ることは、テーブルを結合することよりも「安価」ですが、成熟したRDBMSは、サウンドデータベース設計の一部であるため、結合を実行するために高度に最適化されています。外部キー制約(最も一般的な制約)を介した結合は、特に最適化されています。そしてもちろん、適切な索引付けは不可欠です。

データベースを正規化し、できるだけ少ないクエリで実行する必要があります

これを提示する方法は、これらの「高価な」結合を防止した結果のようです。その逆は真実です。正規化を行うと、常により多くのテーブルが生成されるため、非正規化データスキーマの場合と同じデータをクエリするための結合が増えます。 (まあ、あなたに公平を期すために、後で「私たちはEAVを防ぐので、参加する」と言います)。

非正規化が望ましいものにならない限り、エンティティ属性値アプローチ(EAV)は避けるべきです。

EAVはすべて非正規化です。 EAVって何なのかよくわからない印象です。

EAV設計では、関係の属性(別名fields、またはcolumns)、データベースtable)はリレーションから取り出され、属性テーブルにレコードとして保存されます。 valuesは、Attributesテーブルへの外部キーとEntityテーブル。属性テーブルのレコードは、1つの事実を表しています。これは、エンティティZの属性Yの値Xです。

したがって、EAVを厳密に適用した場合、トーナメントの開始日、終了日、およびコストを知りたい場合は、PGTournamentテーブルをクエリして、属性と値に結合する必要があります(WHERE属性の条件)。これは、EAVなしのゼロではなく2つの結合です。

ほとんどの場合、EAVは悪い設計です。これは、代替手段がない場合に使用されます(たとえば、サンプルの新しい分析を毎日発明できるラボアプリケーションでは、サンプルテーブルのフィールドの固定セットでは不十分です)。

あなたの場合、EAVを導入する理由は何もありません。なぜそれを取り上げたのかわかりません。 EAVと1:1の関連付けを混同しているからだと思います。読む。

つまり、OOPのSOLID原則を遵守する必要があります。

EFクラスモデルはデータアクセスレイヤーの一部です。ドメインモデルではありません!少なくとも、それが最初の責任ではありません。クラスプロパティは、データアクセスを容易にする必要があります。これは、2つのOOPアンチパターンを言及するために、双方向の関係とIdプロパティが存在することを意味します。そして、実際のOOP残念:クラスは、貧血。EFクラスcanをドメインクラスとして使用する場合、これは単なる ボーナス です。

List<>タイプのない仮想プロパティ

このようなプロパティは、他のエンティティに「ナビゲート」するため、ナビゲーションプロパティと呼ばれます。リストはコレクションナビゲーションプロパティで、エンティティタイプのプロパティ(List<>タイプなし)はリファレンスナビゲーションプロパティです。それらは仮想である必要はありません。それらが仮想である場合、EFはプロパティを遅延ロードできる場合があります。

これは、1対1の関係であることを意味します

どうして?多くの場合、参照ナビゲーションプロパティは1:n関連付けの「1」の部分です。あなたの参照プロパティのほとんどはそのようなものだと思います。たとえば、GameGenreです。同じGameGenreの-​​manyトーナメントがあると思います。 nGameGenreコレクションがない場合でも、これは1(ジャンル)からTournaments(トーナメント)への関連付けです。多分TournamentSettingsMainImageだけが実際の1:1関連付けです。

1:1関連付けは、1つのエンティティに属するデータを複数のテーブルに分散します。それを行うには非常に正当な理由があり得る。それらの1つは、MainImageのようないくつかのblobの重いペイロードなしで軽量データのクエリを容易にすることです。もう1つは、機密データを公開データから分離することです。または、特殊なデータ(たまに照会される)からの一般的なデータ(照会されることが多い)、おそらくTournamentSettings

さて、最後に、あなたの質問:

entity Frameworkでモデリングする場合、OOPアプローチよりも完全に正規化された設計を優先する必要がありますか?

リンゴとオレンジを比較しています。正規化された設計はデータベースです、OOPはクラスモデルです。しかし、何か好都合な場合は、正規化された設計です。巧妙に設計されたデータベース設計は、あらゆるデータベースのアプリケーションにとって極めて重要です。それ以外はすべて続きます。 EFクラスモデルは、必ずデータベース構造を厳密に反映します。前述のとおり、データアクセスレイヤーと見なす必要があります。

ただし、ビジネスロジックをモデル化するときは常に、SOLIDとしてできる限り実行するようにしてください。つまり、EFによってクエリされたエンティティから専用のドメインモデルを作成する必要がある場合があります。また、EFクラスを拡張して動作とデータをカプセル化することもできます(OOPがすべてです)。

6
Gert Arnold

Erg、これが私がEFを嫌う理由です。

インデックスを作成する場合、結合は高価ではありません

非リストプロパティは常に1対1の関係であるとは限らず、多対1の場合もあります。

データベースを確認する必要がある場合、データベースの正規化は非常に優れています。 (それが良い他の理由と同様に)EFは「人間にとって難しい」DBを作成して読み取ることができます

可読性が高く柔軟なデータベースの場合、クラスごとに1つのテーブルがあり、主キーが1つ必要です。外部キーによって表される関係、または多対多の非クラステーブルの結合

1
Ewan