实体框架7中的奇怪缓存问题

时间:2016-04-07 09:47:50

标签: c# asp.net .net asp.net-mvc entity-framework

我发现了一些非常具体的内容,并想知道是否有人面临同样的问题。

我的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 Manager运行SP会返回正确的结果,但我的C#/ EF端却没有。在我脑海中唯一合乎逻辑的事情就是某种东西以某种方式被缓存在我迫切需要绕过的引擎盖下?!

1 个答案:

答案 0 :(得分:3)

您加载的实体会缓存在DbContext(每个DbSet的{​​{1}}集合中)。

有几种选择:

  1. 使用Local查询:

    AsNoTracking

    这应该完全避免对此查询进行实体框架缓存

  2. 为每个查询使用新的return _context.Set<DriverDTO>() .AsNoTracking() .FromSql("dbo.New_User_List @OrganisationId = {0}, @IsManager = {1}", organisationId, isManager) .ToList(); 实例

  3. 或者,在发出查询之前从上下文中分离所有缓存的实体......类似于(未经测试):

    DbContext

    请注意,与您的想法相反,您无法使用_context.Set<DriverDTO>().Local.ToList().ForEach(x=> { _context.Entry(x).State = EntityState.Detached; }); ,因为这会将您的实体标记为已删除(因此,如果您_context.Set<DriverDTO>().Local.Clear()之后,它就会被删除从数据库中删除实体),因此在尝试使用本地缓存时要小心。

  4. 除非您需要使用单个SaveChanges或者已经收到SP附带的实体,否则我会选择#2。否则,我会去#1。我把#3放在那里是为了完整性,但除非有必要,否则我要避免使用本地缓存进行修改。