我正在创建服务器端Blazor应用程序。以下代码位于Startup.cs
中。
services.AddDbContext<MyContext>(o => o.UseSqlServer(Configuration.GetConnectionString("MyContext")), ServiceLifetime.Transient);
services.AddTransient<MyViewModel, MyViewModel>();
在ViewModel中:
public class MyViewModel : INotifyPropertyChanged
{
public MyViewModel(MyContext referenceContext)
{
_myContext = myContext;
}
public async Task<IEnumerable<Dto>> GetList(string s)
{
return await _myContext.Table1.where(....)....ToListAsync();
}
并在剃须刀文件中。
@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);
}
}
但是,有时单击搜索按钮时会发生以下错误?
System.InvalidOperationException:'在上一个操作完成之前,第二个操作在此上下文上开始。这通常是由使用相同DbContext实例的不同线程导致的。有关如何避免DbContext线程问题的更多信息,请参见https://go.microsoft.com/fwlink/?linkid=2097913。'
答案 0 :(得分:2)
就我而言,我解决了变成AddDbContext ServiceLifetime.Transient
services.AddDbContext<MY_Context>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")),
ServiceLifetime.Transient);
答案 1 :(得分:1)
您可以尝试为每个请求创建一个新范围:
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();
}
}
Daniel Roth(Blazor产品经理)在谈论Using Entity Framework Core with Blazor
答案 2 :(得分:0)
错误消息与EF上下文一次不能执行多个操作有关。
我的理解是,如果您在页面上,则可以通过SingalR连接与“服务”文件保持恒定连接。
如果您的页面多次调用该服务,则可能是在完成前一个上下文之前调用了Context执行操作。
我在服务的整个生命周期中没有一个Context实例,而是为每个调用创建了一个实例。似乎可以缓解此问题,但是我不确定它是否被视为“最佳实践”。
例如,
public class MyService
{
private MyContext Context => new MyContext(new DbContextOptions<MyContext>()));
private async Task DoSomething()
{
await using var context = this.Context; //New context for the lifetime of this method
var r = await context.Something
.Where(d => d....)
.AsNoTracking()
.FirstOrDefaultAsync()
.ConfigureAwait(false);
// context gets disposed of
// Other code
}
private async Task DoSomethingElse()
{
await using var context = this.Context; //New context for the lifetime of this method
var r = await context.Something
.Where(d => d....)
.AsNoTracking()
.FirstOrDefaultAsync()
.ConfigureAwait(false);
// context gets disposed of
// Other code
}
}
答案 3 :(得分:0)
我解决了这个问题,但是我认为我已经失去了工作单位,因为现在我拥有多个dbContex:
构造函数:
private AppDbContext _db;
protected override void OnInitialized()
{
_db = new AppDbContext();
var query = _db.Set<Group>().AsQueryable();
}
然后我将其丢弃:
public void Dispose()
{
_db?.Dispose();
}