EntityFramework正在缓存旧的过时数据,我不知道如何阻止它

时间:2017-01-28 04:28:31

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

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

室 用户 岗位 postRevision

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

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

我的用户有头像属性。 当我更新用户的头像时,我删除了他们的旧头像,并更新到新的头像。然后在房间里,所述用户的帖子(postRevisions真的)不再具有友好的化身,现在他们有一个破碎的图像图标。我还在开发中,所以在多用户场景中不会发生这种情况。这只是我从更改头像的mvc控制器跳转到显示帖子的信号器/敲门页面。

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

在我的控制器中我有这段代码:

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" });

在我的集线器中,我有一个用于获取帖子页面的代码段:

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>();

2 个答案:

答案 0 :(得分: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?

答案 1 :(得分:1)

我想通过添加

来压缩这个
ServiceLifetime.Transient

到我的AddDbContext调用,使DB上下文具有短暂的生命周期。因此,每个请求都会创建一个新的上下文。

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