【问题标题】:EntityFramework is caching old outdated data, and I don't know how to stop itEntityFramework 正在缓存旧的过时数据,我不知道如何阻止它
【发布时间】:2017-06-13 20:44:25
【问题描述】:

我正在创建一个通信应用程序(使用 .net core 1.1 mvc 和 signalr/knockout )并且我有以下 pocos:

房间 用户 邮政 修改后

posts 是 postRevision 的容器,为方便起见引用了最新的修订版

其他一切都如您所想。我显然省略了很多细节。

我的用户有一个头像属性。 当我更新用户的头像时,我会删除他们的旧头像,然后更新到新头像。然后在房间里,所述用户的帖子(实际上是postRevisions)不再有一个友好的头像,现在他们有一个损坏的图像图标。我仍在开发中,所以这不会发生在多用户场景中。这只是我从更改头像的 mvc 控制器跳转到显示帖子的信号器/淘汰赛页面。

当我停止并运行服务器时,图像是固定的。 看起来实体框架正在缓存结果而不是更新。

在我的控制器中,我有这个代码 sn-p:

user.Avatar = imageId.ToString();
_context.Entry(user).State = EntityState.Modified;
await _context.SaveChangesAsync();

_context.Entry(user).State = EntityState.Detached;
return new JsonResult(new { status = "sucess" });

在我的中心,我有这个 sn-p 用于获取一页帖子:

data =  await _context.Posts
    .Include(x=> x.LatestRevision)
    .Include(x => x.LatestRevision.Blob)
    .Include(x => x.LatestRevision.Creator)
    .Where(x=> x.Room.Id == roomId 
        && x.Id < currentPostId)
    .OrderByDescending(x => x.Id)
    .Take(_roomPageSize).ToListAsync();

我不确定如何告诉信号器上下文进行更新,特别是因为该页面未打开,并且理论上该页面超出范围,因此甚至尚未创建该上下文。 这是我的 Startup.cs 的相关部分

services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

【问题讨论】:

  • 你是同一个 DbContext 实例吗?如果你这样做了,那么这可能就是问题所在。
  • 您在何处/何时创建和处置_context
  • @GertArnold 我正在使用标准的 IoC 依赖注入器,并将上下文作为控制器上的构造函数参数。这就是 startup.cs 文件所暗示的。我认为您对 .net core 没有太多经验。
  • @Pawel :我不这么认为,但这实际上取决于如何为实体框架上下文设置 IoC DI。我想不是。不过不确定。
  • 它只表明你在IoC容器中注册了上下文。但是如果你在控制器中使用构造函数注入,那么每个请求都必须有一个新的上下文。所以这不是上下文缓存的东西。必须是其他一些缓存机制。

标签: entity-framework caching signalr asp.net-core-mvc .net-core


【解决方案1】:

问题在于每个上下文的缓存系统实际上没有将它们的更改相互通信。

我知道与旧数据一起显示的确切用户对象,我打电话给

_context.Entry(user).State = EntityState.Detached;

在中心运行我的查询之前。这什么也没做。旧数据仍在显示。 (在实际使用中不会这么简单,但我现在是系统中唯一的用户)

最终的工作是将这一行添加到我在中心的查询中:

.AsNoTracking()

这意味着我失去了所有缓存,因为 99% 的更改将正确地通过集线器上下文,这看起来很可惜,但它现在可以工作了。

我想知道我是否不应该更改在 MVC 端保存对象的方式,以便我的操作使用集线器上下文,这样它总是在循环中。 我必须在 MVC 端的几个位置添加 .AsNoTracking(),但这是放置它的更好位置。

这里有一篇关于如何做到这一点的帖子: SignalR + posting a message to a Hub via an action method

-edit:以上链接仅用于调用客户端方法。目前还没有调用服务器端集线器代码的好方法。见Use Hub methods from controller?

【讨论】:

    【解决方案2】:

    我最后通过添加

    ServiceLifetime.Transient
    

    对我的AddDbContext 调用,使数据库上下文具有短暂的生命周期。因此,每次从服务容器请求时都会创建一个新的上下文。

    https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1#service-lifetimes

    services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")), ServiceLifetime.Transient);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-25
      • 2023-03-09
      • 2011-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多