2016-04-07 7 views
1

私は非常に具体的な何かに出くわして、そこにいる誰かが同じ問題に直面しているのか疑問に思いました。 (ストアドプロシージャで)Entity Framework 7の奇妙なキャッシングの問題

私のSQLクエリはシンプルですが、私はそれを少ししかし、簡略化されました:

BEGIN 
     SELECT DISTINCT 
      [ANU].[OldUserId] AS [ID] 
      ,[ANU].[Email] 
     FROM 
      [dbo].[AspNetUsers] AS [ANU] 
     INNER JOIN 
      [dbo].[User] AS [U] 
     ON 
      [U].[ID] = [ANU].[OldUserId] 
    END 

かなりシンプルに、そしてSQL Management Studioを介して直接実行するとSPは大丈夫です。

はしかし、私のようなエンティティフレームワークを経由して、それを実行します。

[ResponseCache(Duration = 0)] // used this out of desperation 
public List<DriverDTO> GetByOrganisation(int organisationId, bool isManager) 
{ 
     return _context.Set<DriverDTO>().FromSql("dbo.New_User_List @OrganisationId = {0}, @IsManager = {1}", organisationId, isManager).ToList(); 
} 

DriverDTO:

public class DriverDTO 
{ 
     [Key] // tried removing this also 
     public int ID { get; set; } 
     public string Email { get; set; } 
} 

それが実行され、罰金、結果を持ち帰ります。しかし、これらの結果はキャッシュに入れられています。最初の呼び出し後にSPを呼び出すたびに、レコードを更新しても同じ結果が返されます。だから、私はユーザーのレコードを編集し、電子メールを変更する - 元々フェッチされた電子メールは常に戻ってくると言う。

また、SQLマネージャを使用してSPを実行すると、正しい結果が得られますが、C#/ EF側には反映されません。ここで私の頭の中で唯一の論理的なことは何かが何とか私が必死に周りに行く必要があるフードの下にキャッシュされているということです!

答えて

2

ロードされたエンティティは、DbContext(各DbSetLocalコレクション)にキャッシュされます。クエリの使用AsNoTracking

  1. return _context.Set<DriverDTO>() 
          .AsNoTracking() 
          .FromSql("dbo.New_User_List @OrganisationId = {0}, @IsManager = {1}", organisationId, isManager) 
          .ToList(); 
    

    このこのクエリのために完全にEntity Frameworkのキャッシングを避ける必要があり

  2. を使用して、新しいDbContext例えば

    は、いくつかのオプションがあります各クエリ

  3. また、あなたのクエリを発行する前に、コンテキストからすべてのキャッシュされたエンティティを切り離す...(未テスト)のようなもの:1が考えるかもしれないものとは反対の、あなたがこのことから、_context.Set<DriverDTO>().Local.Clear()を使用することができない、ということ

    _context.Set<DriverDTO>().Local.ToList().ForEach(x=> 
    { 
        _context.Entry(x).State = EntityState.Detached; 
    }); 
    

    お知らせあなたのエンティティを削除済みとしてマークします(したがって、SaveChangesの場合はデータベースからエンティティを削除します)ので、ローカルキャッシュを試している場合は注意してください。

あなたは、単一のDbContextを使用するか、またはそれに接続されているSPから受け取った実体を持つ必要性がない限り、私は#2のために行くと思います。そうでなければ、私は#1に行きます。私は完全性のため#3を入れましたが、厳密に必要でない限り、ローカルキャッシュでのマングリングは避けています。

+1

あなたは今日、私のベーコンを大きなものに保存しました、ありがとうございます! .AsNoTracking()関数は、私のために絶対的な治療をしてくれました。私のシナリオでは、最も単純な方法です。私はこれが他人にも役立つことを願っています –

+1

@ChrisDixon喜んで助けました。副次的な問題として、 'AsNoTracking'クエリは、通常のEFクエリよりメモリが半分以下で、はるかに高速です。(基本的には、あなたのコンテキストがクエリにのみ使われ、更新/削除には使われません) – Jcl

+0

賢明なアドバイス。毎日何か新しいことを学び、私のシステムを劇的にスピードアップします! –