ca9*_*3d9 9 c# entity-framework entity-framework-core blazor blazor-server-side
我正在创建一个服务器端 Blazor 应用程序。以下代码位于Startup.cs
.
services.AddDbContext<MyContext>(o => o.UseSqlServer(Configuration.GetConnectionString("MyContext")), ServiceLifetime.Transient);
services.AddTransient<MyViewModel, MyViewModel>();
Run Code Online (Sandbox Code Playgroud)
在 ViewModel 中:
public class MyViewModel : INotifyPropertyChanged
{
public MyViewModel(MyContext myContext)
{
_myContext = myContext;
}
public async Task<IEnumerable<Dto>> GetList(string s)
{
return await _myContext.Table1.where(....)....ToListAsync();
}
Run Code Online (Sandbox Code Playgroud)
并在剃刀文件中。
@inject ViewModels.MyViewModel VM
<input id="search" type="text" @bind="search" />
<input id="search" type="button" value="Go" @onclick="SearchChanged" />
@code {
string search = "";
int currentCount = 0;
async void SearchChanged() {
currentCount++;
dtos = GetList(search);
}
}
Run Code Online (Sandbox Code Playgroud)
但是,有时单击搜索按钮时会出现以下错误?
System.InvalidOperationException: '在上一个操作完成之前,在此上下文中启动了第二个操作。这通常是由使用相同 DbContext 实例的不同线程引起的。有关如何避免 DbContext 线程问题的详细信息,请参阅https://go.microsoft.com/fwlink/?linkid=2097913。
dan*_*era 13
官方指南:https : //docs.microsoft.com/ca-es/aspnet/core/blazor/blazor-server-ef-core?view=aspnetcore-3.1提供多种解决方案。在我看来,帖子的最佳方法是“创建新的 DbContext 实例”:
创建具有依赖项的新 DbContext 的推荐解决方案是使用工厂。
//The factory
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace BlazorServerDbContextExample.Data
{
public class DbContextFactory<TContext>
: IDbContextFactory<TContext> where TContext : DbContext
{
private readonly IServiceProvider provider;
public DbContextFactory(IServiceProvider provider)
{
this.provider = provider;
}
public TContext CreateDbContext()
{
if (provider == null)
{
throw new InvalidOperationException(
$"You must configure an instance of IServiceProvider");
}
return ActivatorUtilities.CreateInstance<TContext>(provider);
}
}
}
Run Code Online (Sandbox Code Playgroud)
注入工厂:
services.AddDbContextFactory<ContactContext>(opt =>
opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db")
.EnableSensitiveDataLogging());
Run Code Online (Sandbox Code Playgroud)
使用工厂:
private async Task DeleteContactAsync()
{
using var context = DbFactory.CreateDbContext();
Filters.Loading = true;
var contact = await context.Contacts.FirstAsync(
c => c.Id == Wrapper.DeleteRequestId);
if (contact != null)
{
context.Contacts.Remove(contact);
await context.SaveChangesAsync();
}
Filters.Loading = false;
await ReloadAsync();
}
Run Code Online (Sandbox Code Playgroud)
您可以尝试为每个请求创建一个新范围:
public class MyViewModel : INotifyPropertyChanged
{
protected readonly IServiceScopeFactory _ServiceScopeFactory;
public MyViewModel(IServiceScopeFactory serviceScopeFactory)
{
_ServiceScopeFactory = serviceScopeFactory;
}
public async Task<IEnumerable<Dto>> GetList(string s)
{
using (var scope = _ServiceScopeFactory.CreateScope())
{
var referenceContext = scope.ServiceProvider.GetService<MyContext>();
return await _myContext.Table1.where(....)....ToListAsync();
}
}
Run Code Online (Sandbox Code Playgroud)
在以下屏幕截图中,您可以看到此问题的示例案例。用户在几个分页元素中快速点击。新请求在前一个请求结束之前开始。
这里 Daniel Roth(Blazor 产品经理)谈论将 Entity Framework Core 与 Blazor 一起使用