2

モデル設計に非常に深いリレーショナルツリーがあります。つまり、ルートエンティティには、より多くのコレクションを含む他のエンティティのより多くのコレクションを含むエンティティのコレクションが含まれています...他の開発者が持っているビジネスレイヤーを開発しますデータの取得/保存などの操作を実行するために使用します。

そして、このような状況に対処するための最善の戦略を考えています。エンティティを取得するときに、EFがすべての依存関係ツリーを解決することを許可することはできません。これは、多くの役に立たないJOINで終わるためです(次のレベルでそのデータが必要ないため、役に立たない可能性があります)。

  • 遅延読み込みを無効にして、必要なものに積極的な読み込みを適用すると、期待どおりに機能しますが、他の開発者が何か新しいこと(最初は考慮されていない新しい要件や機能など)を実行しようとするchild.Parent.Id代わりに呼び出すと、その依存関係は含まれていませんでした。これは悪いことです...しかし、これは「高速エラー」であり、すぐに修正できます。child.ParentIdNullReferenceException

  • 遅延読み込みを有効にすると、child.Parent.Id代わりにアクセスすると、アクセスchild.ParentIdされるたびにDBへのスタンドアロンクエリが終了します。失敗することはありませんが、エラーがなく、パフォーマンスが低下するだけであり、すべてのコードを確認する必要があるため、さらに悪化します。

私はこれら2つの解決策のいずれにも満足していません。

  • nullまたは空のコレクションを含むエンティティがあるのは不満ですが、実際にはそうではありません。

  • EFにDBに対して任意のクエリを実行させることに満足していません。できれば一発ですべての情報を入手したいです。

だから、私は遅延読み込みを無効にし、熱心な読み込みを強制することを含むいくつかの可能な解決策を思いつきますが、どちらが良いかわかりません:

  • コレクションのないテーブルのデータを含むクラスを作成できるためEntityBase、コレクションにアクセスできません。また、関係を含む具体的な実装では、C#では多重継承が許可されていないため、柔軟性があまりないという問題があります。

  • そのメソッド呼び出しで使用できないプロパティを隠すオブジェクトを「マスク」するインターフェイスを作成できます。たとえば、プロパティがある場合User.Roles、グリッドにすべてのユーザーを表示するために、プロパティを解決する必要がないため.Roles、そのようなプロパティを含まないインターフェイス「IUserData」を作成できます。

NullReferenceExceptionしかし、この追加の作業に価値があるかどうかはわかりません。「このプロパティがロードされていません」という高速表示で十分かもしれません。

プロパティが仮想であり、オーバーライド/設定されていない場合、特定の例外タイプをスローすることは可能でしょうか?

どのような方法を使用していますか?

ありがとう。

4

1 に答える 1

8

私の意見では、開発者がデータにアクセスするときに何をしているのか、データがパフォーマンスにどのような影響を与える可能性があるのか​​を理解する必要から開発者を保護しようとしています-これにより、多くのヘルパークラス、基本クラス、インターフェイスを備えた不要な複雑なAPIが発生する可能性があります、など。

開発者がを使用し、user.MiddleName.Trim()それを取得して何か間違ったことをした場合、が値に設定されていることを確認しなかったか、確認しませんでした。彼がアクセスして取得したときも同じです:彼は、ユーザーのをロードするAPIの適切なメソッドをチェックしなかったか、呼び出しませんでした。MiddleNamenullNullReferenceExceptionnullMiddleNameuser.RolesNullReferenceExceptionnullRoles

私はこう言います:ナビゲーションプロパティがどのように機能するか、そしてそれらは明示的に要求されなければならず、開発者がルールに従わない場合はアプリケーションをクラッシュさせる必要があることを説明してください。彼は間違いを理解して修正する必要があります。

ヘルプとして、たとえば次のようなメソッドを使用して、APIで関連データの読み込みを明示的にすることができます。

public User GetUser(int userId);
public User GetUserWithRoles(int userId);

または:

public User GetUser(int userId, params Expression<Func<User,object>>[] includes);

これは次のように呼び出すことができます:

var userWithoutRoles = layer.GetUser(1);
var userWithRoles = layer.GetUser(2, u => u.Roles);

また、遅延読み込みの代わりに明示的な読み込みを利用して、開発者がナビゲーションプロパティを読み込むだけでなく、プロパティにアクセスするときにメソッドを呼び出すように強制することもできます。

2つの追加のコメント:

...遅延読み込み...アクセスされるたびに、DBへのスタンドアロンクエリで終了します。

これを完了するには、 「...まだロードされていません」。ナビゲーションプロパティが同じコンテキスト内にすでにロードされている場合、プロパティに再度アクセスしても、データベースへのクエリはトリガーされません。

できれば一発ですべての情報を入手したいです。

Include複数のクエリが、多くのsを含む1つのクエリよりもパフォーマンスが低下するわけではありません。実際、複雑で熱心な読み込みは、ネットワーク上でのデータの乗算につながり、エンティティの具体化に非常に時間がかかり、複数の遅延または明示的な読み込みクエリよりも遅くなる可能性があります。(これは、クエリのパフォーマンスが、sを含む単一のクエリからsを含まない1000を超えるクエリに変更することで、50倍向上した例です。)Quintessence:特定の状況で最適な読み込み戦略を確実に予測することはできません。パフォーマンスを測定せずに(その状況でパフォーマンスが重要な場合)。IncludeInclude

于 2012-09-02T20:43:58.367 に答える