6

BeforeSaveEntity メソッド内で検証ルールを整理するための良い方法を探していましたが、プロジェクト内の TodoContextProvider.cs: BreezeMvcSPATemplate: ファイルでこのコメントを見つけました。

// A second DbContext for db access during custom save validation. 
// "this.Context" is reserved for Breeze save only!

this.Context が使用できないのはなぜですか?

4

1 に答える 1

10

素晴らしい質問です。答えは明らかではなく、簡単に説明するのは簡単ではありません。試してみます。

EFContextProviderクライアントから保存データを取得し、(最終的に) これらのデータを 内のエンティティに変換しますEFContextProvider.Context。保存が承認されると、この EFEFContextProviderのメソッドが呼び出され、そのすべての内容が 1 つのトランザクションとして保存されます。SaveChangesContext

2 つの潜在的な問題があります。

1. データの完全性とセキュリティ

クライアント データを完全に信頼することはできません。許可されたユーザーが表示または変更できるものを制限するビジネス ルールがある場合は、クライアントから派生したエンティティをデータベースの対応するエンティティと比較する必要があります。

EFContextには、「同じエンティティ」の 2 つのコピーを含めることはできません。同じキーを持つ 2 つのエンティティを保持することはできません。EFContextProvider.Contextしたがって、両方を使用してデータベースからクリーン コピーをフェッチし、コピーを変更して保持することはできません。

クリーン コピーを取得するには 1 秒が必要であり、保存するエンティティの重要な値を2 番目の のクリーン エンティティの値Contextと比較するロジックを記述する必要があります。EFContextProvider.ContextContext

2.クロスエンティティ検証

多くの検証では、値をクリーンなエンティティと比較する必要はありません。

たとえば、やなどのすぐ System.ComponentModel.DataAnnotationsに使用できる属性は、エンティティが自己一貫性があるかどうかを判断するための単純なデータ検証です。値があるか、ないかのどちらかです。値が最大長より小さいか、そうではありません。このようなテストには比較エンティティは必要ありません。RequiredMaxLength

単一のエンティティSystem.ComponentModel.DataAnnotationsでデータ値を比較する独自のカスタム属性を作成できます。on-or-beforeでなければならないというルールがあるかもしれません。これは自己整合性テストでもあり、そのための比較エンティティも必要ありません。order.InvoiceDateorder.ShipDate

これらの種類の検証のみが重要であり、EF を使用している場合は保存処理DbContext中に EF にそれらを実行させることができます。一瞬も必要ありません。Context

しかし、エンティティ間の検証は別の話です。エンティティ間の検証では、エンティティ 'A' は、エンティティ 'B' (およびおそらく 'C'、'D'、'E' など) に対して何らかの条件が真である場合にのみ有効です。たとえば、注文項目には、データベースに既に存在する親注文が必要になる場合があります。

EFContextProvider.Context注文アイテムを検証している時点で、親注文が存在しない可能性が非常に高くなります。

「問題ありません」とあなたは言います。「私は で親に移動しますsomeItem.Order。」

いいえ、あなたがすることはできません。まず、 の遅延読み込みが無効になっているため、機能しませんEFContextProvider.Context。は、主にシリアライゼーション中に循環参照を壊すために遅延読み込みを無効にしますが、サーバー上の「n + 1」バグEFContextProviderを殺すパフォーマンスを防ぐためにも使用します。

エンティティまたは関連するエンティティを自由にロードすることで、これを回避できます。しかし、2 つ目の問題が発生します。検証のために読み込むエンティティが、このバッチで保存しようとしている別のエンティティと競合する可能性があります。

一度にすべてが読み込まれるEFContextProviderわけではありません。Contextエンティティの検証を 1 つずつ開始し、エンティティを に追加しますContext

someItem例を続けて、検証中にの親注文をロードしたとします。その注文は現在 にありEFContextProvider.Contextます。

保存プロセスは次のエンティティに続きます...驚き、驚き...次のエンティティはたまたま同じ親順序です。は、このEFContextProviderコピーを既にコピーがある にアタッチしようとしContextます (ロードしたばかりのもの) ... できません。

衝突があります。2 つのオーダーのうち、どちらが に属しEFContextProviderますか? 検証目的でロードしたばかりのクリーン コピーか、それとも保存する変更を加えたクライアントからのコピーか?

たぶん、あなたは答えを知っていると思います。多分私は同意します。しかし実際には、 にEFContextProviderそのキーを持つ注文が既に存在するため、 は例外をスローしますContext

結論

すべての検証が自己整合性チェックであるEFContextProvider.Context場合は、これだけで十分です。秒を作成する必要はありませんContext

ただし、データ セキュリティに関する懸念や、他のエンティティが関与するビジネス ロジックがある場合は、2 番目がContext必要です。それを使用するには、十分な EF スキルが必要ですContext

これはBreeze や Entity Framework の制限ではありません。重要なビジネス ロジックでは、選択したテクノロジに関係なく、同等のサーバー側の複雑さが要求されます。それが獣の本性です。

于 2013-01-27T08:21:30.330 に答える