高性能と低遅延が不可欠なかなり複雑なエンティティモデルがありますが、水平スケーラビリティは必要ありません。アプリケーションには、自己ホスト型のASP.NET Web APIに加えていくつかのイベントソースがあります。2. Entity Framework 6を使用してPOCOクラスからデータベースにマップします(クラスを生成するために優秀なReverse POCO Generatorを使用します)。Entity Framework - 読み取り専用オブジェクトをキャッシュして共有する方法
イベントが到着するたびに、アプリケーションはエンティティモデルを調整し、EFを介してこのデルタ調整をデータベースに保持する必要があります。同時に、読取り要求または更新要求がWeb APIを介して到着することがあります。
モデルには多くのテーブルとFK関係があり、イベントに反応するためには通常、対象エンティティのすべての関係がロードされている必要があるため、データセット全体をロードするのではなくメモリ内キャッシュに保持することにしました各イベントのオブジェクトグラフ全体。プログラム起動時に
我々は一時的DbContext
を経由して、すべての興味深いClassA
のインスタンス(およびそれに関連する依存関係グラフ)をロードし、(辞書に挿入 - は:下の画像は、我々のモデルの単純化されたバージョンを示してい私たちのキャッシュ)。イベントが到着すると、ClassAインスタンスがキャッシュに格納され、イベントごとにDbContext
(DbSet.Attach()
)にアタッチされます。プログラムはawait-asyncパターンを使用して書き込まれ、複数のイベントを同時に処理できます。ロックを使用してキャッシュされたオブジェクトが同時にアクセスされるのを防ぎます。したがって、キャッシュされたClassA
を1度に1つずつDbContext
にロードできることが保証されます。これまでのところ、とても優れていて、パフォーマンスは優れており、我々はそのメカニズムに満足しています。 しかし、に問題があります。エンティティグラフはClassA
の下にかなり自己完結していますが、読み取り専用のスタティックデータ(イメージのオレンジ色で網掛けされている)を表すPOCOクラスがいくつかあります。我々は、EFが時々不平を言うことを発見しました。
IEntityChangeTrackerの複数のインスタンスでエンティティオブジェクトを参照することはできません。
彼らは同じClassAType
への参照を共有しているため、我々は(我々は異なるDbcontexts
に添付されていても)同時にClassA
のAttach()
2つの異なるインスタンスにしようとしたとき。これは、以下のコードによって実証されています -
ConcurrentDictionary<int,ClassA> theCache = null;
using(var ctx = new MyDbContext())
{
var classAs = ctx.ClassAs
.Include(a => a.ClassAType)
.ToList();
theCache = new ConcurrentDictionary<int,ClassA>(classAs.ToDictionary(a => a.ID));
}
// take 2 different instances of ClassA that refer to the same ClassAType
// and load them into separate DbContexts
var ctx1 = new MyDbContext();
ctx1.ClassAs.Attach(theCache[1]);
var ctx2 = new MyDbContext();
ctx2.ClassAs.Attach(theCache[2]); // exception thrown here
ClassAType
は/静的読み取り専用であり、我々はそれが、各インスタンスは一つだけにロードすることができることを保証したくないというEFを通知する方法はありますDbContext
?これまで私が見つけた問題を回避する唯一の方法は、これらのFK関係を無視するようにPOCOジェネレータを変更することです。そのため、エンティティモデルの一部ではありません。しかし、これは、静的データへのアクセスを必要とする処理方法がClassA
であるため、プログラミングを複雑にする。
こんにちは@Dianaを。私はこれがいくつかの理由で助けになるとは思わない。 1) 'AsNoTracking'を使用すると、オブジェクトは' DbContext'によってキャッシュされないので、 'ClassA'グラフの後続のロードでそれらを再度含める必要があります。 2)エンティティの追跡状態は、オブジェクトそのものではなく、DbContextのプロパティであると考えています。したがって、元のDbContextが配置されていると、トラッキング/トラッキングなしの残りのメモリはありません。 – Rob
あなたが正しいです、エンティティは 'DbContext'から切り離されます、それらのための' Entry'はありません。次に、同じインスタンスを使用する代わりに、異なるClassAグラフごとに、それらのエンティティの新しいインスタンスを作成するというソリューションがあると思います。グラフにそれらを割り当てる前に、それらを複製するようなもの。 – Diana
私はこれらの行に沿った何かがうまくいくと信じていますが、エンティティグラフを読み込むコードにとっては重大な問題になると思います(すべてのClassAを繰り返し、読み込み専用のクラスインスタンスを置き換える必要があります。構造)。私は、静的データクラスのレベルでより宣言的なものを期待していました。 – Rob