web-dev-qa-db-fra.com

Blazor: une deuxième opération a commencé sur ce contexte avant la fin d'une opération précédente

Je crée une application de blazor côté serveur. Le code suivant est dans le Startup.cs.

services.AddDbContext<MyContext>(o => o.UseSqlServer(Configuration.GetConnectionString("MyContext")), ServiceLifetime.Transient);
services.AddTransient<MyViewModel, MyViewModel>();

Et dans la vue de la vue:

public class MyViewModel : INotifyPropertyChanged
{
    public MyViewModel(MyContext myContext)
    {
        _myContext = myContext;
    }

    public async Task<IEnumerable<Dto>> GetList(string s)
    {
        return await _myContext.Table1.where(....)....ToListAsync();
    }

Et dans le fichier de rasoir.

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

Cependant, parfois, l'erreur suivante se produit lorsque vous cliquez sur le bouton de recherche?

System.InvalidoperationException: "Une deuxième opération a commencé sur ce contexte avant une opération précédente terminée. Ceci est généralement causé par différents threads en utilisant la même instance de DBContext. Pour plus d'informations sur la manière d'éviter les problèmes de filetage avec DBContext, voir https://go.microsoft.com/fwlink/?LinkID=209791 . '

9
ca9163d9

Je résolvai le problème, mais je pense avoir perdu l'unité de travail parce que maintenant j'ai plus d'un dBContex:

Constructeur:

private AppDbContext _db;
protected override void OnInitialized()
{
    _db = new AppDbContext();
     var query = _db.Set<Group>().AsQueryable();
}

et plus tard je le dispose:

public void Dispose()
{
    _db?.Dispose();
}
0
Ali Borjian

Le message d'erreur est de faire avec le fait que le contexte EF ne peut pas effectuer plus d'une opération à la fois.

Ma compréhension est que si vous êtes sur une page, vous avez une connexion constante jusqu'au fichier "Service" via une connexion SingAnR.

Si votre page effectue plusieurs appels au service, il est possible que le contexte soit appelé pour effectuer une opération avant de terminer la précédente.

Plutôt que d'avoir une instance du contexte pour la durée de vie du service, j'ai créé une instance par appel. Il semble atténuer ce problème, mais que ce soit considéré comme "meilleure pratique", je ne suis pas encore sûr.

Donc, par exemple:

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
    }
}
0
DrGriff