5

次のように、独自の DbSet を定義しようとしています。

public class MyDbSet<TEntity> : DbSet<TEntity>
    where TEntity : class
{
    public override TEntity Add(TEntity entity)
    {
      ....

そしてそれをDbContextで使用します

    public MyDbSet<User> Users { get; set; }

私が直面している問題はUsers、実行時に null になる (したがって役に立たない) ことですが、その理由はわかりません。のようなものdb.Users.Any(がスローされ"value cannot be null"ます; 代わりにDbSetを置き換えて使用すると

    public DbSet<User> Users { get; set; }

すべて正常に動作します。

独自の派生クラスを使用できるように、この問題を修正できるかどうか、またその方法を知っている人はいますか?

編集:

いくつかのコメントを受け取った後、なぜこれを行うのかを明確にします。コードを変更せずに、データ取得メカニズムから別のメカニズムに簡単に切り替えられるようにしたいからです。たとえば、メモリ内でキャッシュを行うことにした場合 (キャッシュは単なる例であり、他のものも変更したい場合があります) 、データベースにクエリを実行する代わりに、 Any/Find/...inMyDbSetをオーバーライドして辞書から読み取るだけで、残りの部分はそのままにします。コードは変更されません。このようにして、コードはデータがどのように取得されるかを気にせずに「通常の」操作を実行します。したがって、誰かがクラスを拡張せずにこれを行うメソッドを指すことができれば、DbSetそれも質問に答えます。

どうもありがとう

4

1 に答える 1

1

私はこの道を数回行ってきましたが、このように機能させたいという願望を理解していますが、私の経験では、実行可能ではないか、実行可能であれば努力する価値がありません. その理由は、多くの異なるストレージ エンジン (メモリ内キャッシュを含む) には、EF に簡単に適合できない違いがあるためです。たとえば、DbSet の些細なインメモリ キャッシュ実装では、トランザクション、レイジーまたはイーガー ロード スキームなどが受け入れられない場合があります。私の考えでは、Azure テーブル ストレージでスワップできるようにしたいと考えていました。ただし、その並べ替え、ページング、およびクエリは、SQL Server ほどリッチではありません。SQL では実行できるが、Azure Tables では実行できないクエリがいくつかあります。結局、私は常に、EF の背後にある永続化エンジンを交換する機能が魅力的に聞こえると信じています。

キャッシュをサポートする必要があり、ASP.NET Web API を実行していた場合は、その時点で API 要求/応答がキャッシュされるように、ASP.NET キャッシュを使用することを検討します。

さまざまなリレーショナル DB ベンダーのサポートが必要な場合は、サード パーティの EF プロバイダーを使用します。さまざまなデータベースの Entity Framework プロバイダーのリスト

データ レイヤー内のキャッシュ、または大幅に異なる複数のストレージ エンジン (Mongo、Azure、SQL など) が必要な場合は、EF レイヤーの "上" で行います。このようなもの:

 public interface ISomeDataProvider
 {
     SomeType Find(int id); 
     ....
 }

 public class EfDataProvider : ISomeDataProvider
 {
     private SomeAppDbContext db = new SomeAppDbContext();
     public SomeType Find(int id){
         return db.SomeTypes.Find(id);
     }

 }

 public class AzureTableDataProvider : ISomeDataProvider
 {
     public SomeType Find(int id){
         return //Azure Table code
     }

 }

 public class CachingDataProvider : ISomeDataProvider
 {
     private ISomeDataProvider source;
     private static IList<SomeType> cache = new List<SomeType>(); //List used here, but could use .NET Cache, Redis, etc.
     public CachingDataProvider(ISomeDataProvider source){
            this.source = source;
     }
     public SomeType Find(int id){
         var result = cache.SingleOrDefault(x=>x.Id == id)
         if(result == null){
             result = source.SingleOrDefault(x=>x.Id == id)
             if(result != null) cache.Add(result); //Again, trivial cache example.  Cache expiration, refresh, loading, etc. should be considered per-app
         }
         return result
     }

 }

とはいえ、私のアプリケーションの大部分では、考えてみると、永続化エンジンを交換する機能は実際には要件ではありません。私の顧客は、「SQL が必要な人もいれば、Azure テーブルが必要な人」もいません。これは私たちが行っている作業の種類によるものかもしれませんが、最終的には依存関係になり、EF に直接コーディングします。

于 2015-03-03T15:47:24.927 に答える