我正在创建一个通信应用程序(使用.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>();
答案 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);