我有 Blazor Interactive Server 应用程序。在我的几个页面上,我有一个组件,用户可以在其中注册活动。有 4 个按钮(否、未定、有兴趣、参加)。当他们单击按钮时,会触发一个事件,从数据库读取 2 条记录,使用注册状态更新它们,然后保存它们。
用户快速点击几个按钮(不知道为什么)。最终结果是我收到一个 DbUpdateConcurrencyException,因为它读取多个事件处理程序调用中的记录,更新它们,然后保存它们,并且在第一次抛出 DbUpdateConcurrencyException 之后进行所有操作。
有没有办法强制每个会话同步处理此事件处理程序?涉及的记录是用户记录,因此会话之间不会发生冲突,除非用户通过 2 个浏览器连接并同时单击 - 在这种情况下很难。
听起来这里的问题实际上与数据库在组件中的连接方式有关。您是否将 DbContext 注入到组件中,然后在整个组件中使用相同的实例?
如果是这样,这将是问题的原因。
在 Blazor 中,注入服务的范围仅限于电路的生命周期(与更传统的 Web 应用程序中的请求生命周期相反)。 DbContexts 不允许在您看到的同一实例上并发工作。
Microsoft 的建议是每个操作都应该有一个 DbContext 实例(而不是组件的公共实例)。
实现这一点的方法是在组件中注入一个DbContextFactory,然后就可以轻松创建实例了。
@inject IDbContextFactory<ContactContext> DbFactory
private async Task Undecided()
{
// create a DbContext that is scoped to just this action
using var context = DbFactory.CreateDbContext();
// do DB stuff here
await context.SaveChangesAsync();
}
private async Task Interested()
{
using var context = DbFactory.CreateDbContext();
// do DB stuff here
await context.SaveChangesAsync();
}
您可以在这里阅读更多相关信息: