Entity Framework Core: una seconda operazione avviata in questo contesto prima del completamento di un'operazione precedente


98

Sto lavorando a un progetto ASP.Net Core 2.0 utilizzando Entity Framework Core

<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.1" />
  <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0"/>

E in uno dei miei metodi di elenco ricevo questo errore:

InvalidOperationException: A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.
Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.EnterCriticalSection()

Questo è il mio metodo:

    [HttpGet("{currentPage}/{pageSize}/")]
    [HttpGet("{currentPage}/{pageSize}/{search}")]
    public ListResponseVM<ClientVM> GetClients([FromRoute] int currentPage, int pageSize, string search)
    {
        var resp = new ListResponseVM<ClientVM>();
        var items = _context.Clients
            .Include(i => i.Contacts)
            .Include(i => i.Addresses)
            .Include("ClientObjectives.Objective")
            .Include(i => i.Urls)
            .Include(i => i.Users)
            .Where(p => string.IsNullOrEmpty(search) || p.CompanyName.Contains(search))
            .OrderBy(p => p.CompanyName)
            .ToPagedList(pageSize, currentPage);

        resp.NumberOfPages = items.TotalPage;

        foreach (var item in items)
        {
            var client = _mapper.Map<ClientVM>(item);

            client.Addresses = new List<AddressVM>();
            foreach (var addr in item.Addresses)
            {
                var address = _mapper.Map<AddressVM>(addr);
                address.CountryCode = addr.CountryId;
                client.Addresses.Add(address);
            }

            client.Contacts = item.Contacts.Select(p => _mapper.Map<ContactVM>(p)).ToList();
            client.Urls = item.Urls.Select(p => _mapper.Map<ClientUrlVM>(p)).ToList();
            client.Objectives = item.Objectives.Select(p => _mapper.Map<ObjectiveVM>(p)).ToList();
            resp.Items.Add(client);
        }

        return resp;
    }

Sono un po 'perso soprattutto perché funziona quando lo eseguo localmente, ma quando eseguo la distribuzione sul mio server di gestione temporanea (IIS 8.5) mi viene visualizzato questo errore e ha funzionato normalmente. L'errore ha iniziato a comparire dopo aver aumentato la lunghezza massima di uno dei miei modelli. Ho anche aggiornato la lunghezza massima del corrispondente modello di visualizzazione. E ci sono molti altri metodi di elenco che sono molto simili e funzionano.

Avevo un lavoro Hangfire in esecuzione, ma questo lavoro non utilizza la stessa entità. Questo è tutto ciò che posso pensare sia rilevante. Qualche idea su cosa potrebbe causare questo?


1
Controlla questo .
Berkay

2
@Berkay ho visto questa e molte altre domande simili e le ho provate. Il mio metodo era asincrono e l'ho sincronizzato per evitare questi problemi. Provo anche a rimuovere la mappatura, ho anche provato a rimuovere .ToPagedList continua a lanciare l'errore.
André Luiz

Sarebbe bello vedere una traccia completa dello stack
Evk

E per sapere se sono abilitati più risultati attivi
Jay

Avendo avuto lo stesso problema, ho scoperto di avere numeri interi nullable nella tabella del database. non appena ho impostato le proprietà del mio modello di entità per corrispondere agli int nullable, tutto ha iniziato a funzionare, quindi i messaggi erano fuorvianti per me ...!
AlwaysLearning

Risposte:


98

Non sono sicuro se stai usando IoC e Dependency Injection per risolvere il tuo DbContext dove mai potrebbe essere usato. Se lo fai e stai usando IoC nativo da .NET Core (o qualsiasi altro IoC-Container) e ricevi questo errore, assicurati di registrare il tuo DbContext come Transient. Fare

services.AddTransient<MyContext>();

O

services.AddDbContext<MyContext>(ServiceLifetime.Transient);

invece di

services.AddDbContext<MyContext>();

AddDbContext aggiunge il contesto come con ambito, il che potrebbe causare problemi quando si lavora con più thread.

Anche le operazioni async / await possono causare questo comportamento, quando si usano espressioni lambda asincrone.

Aggiungerlo come transitorio ha anche i suoi svantaggi. Non sarai in grado di apportare modifiche a un'entità su più classi che utilizzano il contesto perché ogni classe otterrà la propria istanza di DbContext.

La semplice spiegazione di ciò è che l' DbContextimplementazione non è thread-safe. Puoi leggere di più su questo qui


2
Quando utilizzo transitorio ottengo i seguenti errori di connessione (chiusi o eliminati) 'OmniService.DataAccess.Models.OmniServiceDbContext'. System.ObjectDisposedException: impossibile accedere a un oggetto eliminato. Una causa comune di questo errore è l'eliminazione di un contesto che è stato risolto dall'inserimento di dipendenze e quindi il tentativo successivo di utilizzare la stessa istanza di contesto altrove nell'applicazione. Ciò può verificarsi se si chiama Dispose () nel contesto o si racchiude il contesto in un'istruzione using. ... Nome oggetto: "AsyncDisposer".
David

5
Ciao David! Immagino che tu stia usando Task.Run(async () => context.Set...)senza aspettarlo o creare un contesto db con ambito senza attendere il risultato. Ciò significa che il tuo contesto è probabilmente già eliminato quando vi si accede. Se utilizzi Microsoft DI, devi creare tu stesso un ambito di dipendenza al suo interno Task.Run. Dai un'occhiata anche a questi link. stackoverflow.com/questions/45047877/... docs.microsoft.com/en-us/dotnet/api/...
alsami

3
Come sottolineato in precedenza, se ti perdi a chiamare un metodo asincrono con la parola chiave await, dovrai affrontare questo problema.
Yennefer

1
Questo può andare bene, ma si deve essere più attenti alla durata desiderata e all'ambito di risoluzione dell'accesso ai dati piuttosto che usare disinvoltamente il transitorio senza sfumature delle circostanze. In effetti, considererei raro che si desideri un contesto di dati transitorio. Se l'ambito di un'unità di lavoro è qualcosa che coinvolge più di una singola operazione sui dati, l'ambito della transazione dovrebbe estendersi più di questo. La risoluzione del contesto dei dati dovrebbe rispecchiare l'ambito della tua unità di lavoro. Questo è qualcosa su cui riflettere e questa non è una risposta valida per tutti.
Dave Rael,

3
@alsami sei il mio eroe. 6 ore di doloroso debugging. Questa era la soluzione. Se qualcun altro inserisce IHttpContextAccessor in DbContext e le attestazioni sono null, questa è la soluzione. Grazie mille amico.
jcmontx

62

In alcuni casi, questo errore si verifica quando si chiama un metodo asincrono senza la awaitparola chiave, che può essere semplicemente risolto aggiungendo awaitprima della chiamata al metodo. tuttavia, la risposta potrebbe non essere correlata alla domanda menzionata, ma può aiutare a risolvere un errore simile.


5
Questo è successo a me. Cambiare First()a await / FirstAsync()lavorato.
Guilherme

Voto positivo. Vedi anche jimlynn.wordpress.com/2017/11/16/… Jim Lynn "ERRORE DEL QUADRO DI ENTITÀ: UNA SECONDA OPERAZIONE INIZIATA IN QUESTO CONTESTO PRIMA DEL COMPLETAMENTO DI UNA PRECEDENTE OPERAZIONE. NON SI GARANTISCE LA SICUREZZA DEI MEMBRI DELL'ISTANZA".
granadaCoder

Grazie per questo! Questo era esattamente il mio problema ... Ho dimenticato di aggiungere un await su un mdethod asincrono.
AxleWack

È successo anche a me, e questo commento mi ha aiutato mentre cercavo dove avevo dimenticato un'attesa mancante. Una volta trovato, il problema è risolto.
Zion Hai

ha funzionato per me, grazie mille
zoha_sh

43

L'eccezione significa che _contextviene utilizzato da due thread contemporaneamente; o due thread nella stessa richiesta o da due richieste.

La tua _contextdichiarata staticità forse? Non dovrebbe essere.

O stai chiamando GetClientspiù volte nella stessa richiesta da qualche altra parte nel tuo codice?

Potresti già farlo, ma idealmente useresti l'inserimento delle dipendenze per il tuo DbContext, il che significa che lo utilizzerai AddDbContext()nel tuo Startup.cs e il costruttore del tuo controller avrà un aspetto simile a questo:

private readonly MyDbContext _context; //not static

public MyController(MyDbContext context) {
    _context = context;
}

Se il tuo codice non è così, mostracelo e forse possiamo aiutarti ulteriormente.


1
Probabilmente è il lavoro che ho. Sono riuscito a risolvere, vedere la mia risposta. Ma sto contrassegnando il tuo come quello giusto
André Luiz

Il mio codice è esattamente così e spesso teniamo traccia di "Una seconda operazione è iniziata in questo contesto prima del completamento di una precedente operazione asincrona. Utilizza" await "per assicurarti che tutte le operazioni asincrone siano state completate prima di chiamare un altro metodo in questo contesto. Tutti i membri dell'istanza non lo sono garantito per essere thread-safe. - in System.Data.Entity.Internal.ThrowingMonitor.EnsureNotEntered () ".
NMathur

@NMathur Stai usando il tuo _contextoggetto in altri thread? Come all'interno di un Task.Run()per esempio?
Gabriel Luci

@ GabrielLuci tutti i miei metodi sono asincroni come di seguito, questo causerà il problema. La mia conoscenza riguardo a questo argomento è molto scarsa. Potete suggerirmi dove e cosa dovrei leggere in dettaglio per capire questi comportamenti? public async Task <List <Item>> GetItems (int orderId) {List <Item> items = await _context.Item.Where (x => x.OrderId == orderId) .ToListAsync (); restituire articoli; }
NMathur

@NMathur Sembra a posto. Assicurati solo di utilizzare sempre awaitmetodi asincroni. Se non lo usi await, puoi entrare involontariamente nel multi-threading.
Gabriel Luci

11
  • Risolvi il mio problema utilizzando questa riga di codice nel mio file Startup.cs.
    L'aggiunta di un servizio temporaneo significa che ogni volta che il servizio viene richiesto, viene creata una nuova istanza quando si lavora con l'inserimento delle dipendenze

           services.AddDbContext<Context>(options =>
                            options.UseSqlServer(_configuration.GetConnectionString("ContextConn")),
                 ServiceLifetime.Transient);
    

Questo metodo causerà problemi nei casi in cui il numero di transazioni istantanee multiutente è elevato.
hakantopuz

11

Ho avuto lo stesso problema e si è scoperto che il servizio dei genitori era un singelton. Quindi anche il contesto è diventato automaticamente singelton. Anche se è stato dichiarato per Life Time Scoped in DI.

Iniettare un servizio con diverse durate in un altro

  1. Non inserire mai servizi con ambito e transitori nel servizio Singleton. (Questo converte efficacemente il servizio transitorio o con ambito nel singleton.)

  2. Non inserire mai servizi temporanei nel servizio con ambito (questo converte il servizio temporaneo in servizio con ambito)


questo era esattamente il mio problema
Jonesopolis

Questo era anche il mio problema. Stavo registrando una classe gestore come singleton e DbContext come transiente. Ho dovuto utilizzare ServiceProvider all'interno della classe Handler per ottenere un'istanza transitoria dal contenitore DI ogni volta che l'Handler viene colpito
Daiana Sodré,

6

Penso che questa risposta possa ancora aiutare qualcuno e salvare molte volte. Ho risolto un problema simile cambiando IQueryablein List(o in array, collection ...).

Per esempio:

var list=_context.table1.where(...);

per

var list=_context.table1.where(...).ToList(); //or ToArray()...

3
IMHO, questa risposta non merita punti negativi, è solo mal espressa. .ToList () risolve infatti la maggior parte dei problemi "una seconda operazione ..." in quanto forza la valutazione immediata dell'espressione. In questo modo non ci sono operazioni di contesto di accodamento.
vassilag

1
Questo era il problema nel mio caso. Avevo xxx.Contains (z.prop) in una clausola where di una query. xxx doveva essere un array int [] distinto risolto da una query precedente. Sfortunatamente, quando è arrivata la seconda query, xxx era ancora un IQueryable. L'aggiunta di xxx.ToArray () prima della seconda query ha risolto il problema.
Jason Butera

5

Ho avuto lo stesso errore. È successo perché ho chiamato un metodo che è stato costruito come public async void ...invece di public async Task ....


2

Ho affrontato lo stesso problema, ma il motivo non era nessuno di quelli sopra elencati. Ho creato un'attività, creato un ambito all'interno dell'attività e chiesto al contenitore di ottenere un servizio. Ha funzionato bene, ma poi ho utilizzato un secondo servizio all'interno dell'attività e ho dimenticato di richiederlo anche al nuovo ambito. Per questo motivo, il secondo servizio utilizzava un DbContext che era già stato eliminato.

Task task = Task.Run(() =>
    {
        using (var scope = serviceScopeFactory.CreateScope())
        {
            var otherOfferService = scope.ServiceProvider.GetService<IOfferService>();
            // everything was ok here. then I did: 
            productService.DoSomething(); // (from the main scope) and this failed because the db context associated to that service was already disposed.
            ...
        }
    }

Avrei dovuto farlo:

var otherProductService = scope.ServiceProvider.GetService<IProductService>();
otherProductService.DoSomething();

Il contesto non sarebbe esposto solo una volta completata l'esecuzione di tutto nel blocco using?
Sello Mkantjwa

Quando l'azione viene eliminata, tutto viene eliminato in tale ambito. Se hai un'attività in esecuzione in background e tale attività è più lunga dell'azione, avrai questo problema a meno che non crei un nuovo ambito per l'attività, proprio come ho fatto nell'esempio. D'altra parte, se la tua attività potrebbe richiedere molto tempo o se vuoi essere sicuro al 100% che verrà eseguita, potresti dover utilizzare una coda. Se stai usando Azure, puoi usare le code del bus di servizio.
Francisco Goldenstein

2

La mia situazione è diversa: stavo cercando di seminare il database con 30 utenti, appartenenti a ruoli specifici, quindi stavo eseguendo questo codice:

for (var i = 1; i <= 30; i++)
{
    CreateUserWithRole("Analyst", $"analyst{i}", UserManager);
}

Questa era una funzione di sincronizzazione. Al suo interno ho ricevuto 3 chiamate a:

UserManager.FindByNameAsync(username).Result
UserManager.CreateAsync(user, pass).Result
UserManager.AddToRoleAsync(user, roleName).Result

Quando ho sostituito .Resultcon .GetAwaiter().GetResult(), questo errore è andato via.


2

Entity Framework Core non supporta più operazioni parallele in esecuzione sulla stessa DbContextistanza. Ciò include sia l'esecuzione parallela di asyncquery che qualsiasi utilizzo simultaneo esplicito da più thread. Pertanto, await asyncchiama sempre immediatamente o utilizza DbContextistanze separate per operazioni che vengono eseguite in parallelo.


1

Ho un servizio in background che esegue un'azione per ogni voce in una tabella. Il problema è che se itero e modifico alcuni dati tutti sulla stessa istanza di DbContext, si verifica questo errore.

Una soluzione, come menzionato in questo thread, consiste nel modificare la durata di DbContext in transiente definendolo come

services.AddDbContext<DbContext>(ServiceLifetime.Transient);

ma poiché apporto modifiche in più servizi diversi e le eseguo contemporaneamente utilizzando il SaveChanges()metodo, questa soluzione non funziona nel mio caso.

Poiché il mio codice viene eseguito in un servizio, stavo facendo qualcosa di simile

using (var scope = Services.CreateScope())
{
   var entities = scope.ServiceProvider.GetRequiredService<IReadService>().GetEntities();
   var writeService = scope.ServiceProvider.GetRequiredService<IWriteService>();
   foreach (Entity entity in entities)
   {
       writeService.DoSomething(entity);
   } 
}

per poter utilizzare il servizio come se fosse una semplice richiesta. Quindi, per risolvere il problema, ho semplicemente diviso il singolo ambito in due, uno per la query e l'altro per le operazioni di scrittura in questo modo:

using (var readScope = Services.CreateScope())
using (var writeScope = Services.CreateScope())
{
   var entities = readScope.ServiceProvider.GetRequiredService<IReadService>().GetEntities();
   var writeService = writeScope.ServiceProvider.GetRequiredService<IWriteService>();
   foreach (Entity entity in entities)
   {
       writeService.DoSomething(entity);
   } 
}

In questo modo, ci sono effettivamente due diverse istanze di DbContext in uso.

Un'altra possibile soluzione sarebbe assicurarsi che l'operazione di lettura sia terminata prima di iniziare l'iterazione. Ciò non è molto pratico nel mio caso perché potrebbero esserci molti risultati che dovrebbero essere tutti caricati in memoria per l'operazione che ho cercato di evitare utilizzando in primo luogo un Queryable.


1

Innanzitutto, dai un voto positivo (almeno) alla risposta di alsami. Questo mi ha portato sulla strada giusta.

Ma per quelli di voi che fanno IoC, ecco un'immersione un po 'più profonda.

Il mio errore (come gli altri)

Si sono verificati uno o più errori. (Una seconda operazione avviata in questo contesto prima del completamento di un'operazione precedente. Ciò è in genere causato da thread diversi che utilizzano la stessa istanza di DbContext. Per ulteriori informazioni su come evitare problemi di threading con DbContext, vedere https://go.microsoft.com / fwlink /? linkid = 2097913. )

La mia configurazione del codice. "Solo le basi" ...

public class MyCoolDbContext: DbContext{
    public DbSet <MySpecialObject> MySpecialObjects {        get;        set;    }
}

e

public interface IMySpecialObjectDomainData{}

e (nota che MyCoolDbContext viene iniettato)

public class MySpecialObjectEntityFrameworkDomainDataLayer: IMySpecialObjectDomainData{
    public MySpecialObjectEntityFrameworkDomainDataLayer(MyCoolDbContext context) {
        /* HERE IS WHERE TO SET THE BREAK POINT, HOW MANY TIMES IS THIS RUNNING??? */
        this.entityDbContext = context ?? throw new ArgumentNullException("MyCoolDbContext is null", (Exception)null);
    }
}

e

public interface IMySpecialObjectManager{}

e

public class MySpecialObjectManager: IMySpecialObjectManager
{
    public const string ErrorMessageIMySpecialObjectDomainDataIsNull = "IMySpecialObjectDomainData is null";
    private readonly IMySpecialObjectDomainData mySpecialObjectDomainData;

    public MySpecialObjectManager(IMySpecialObjectDomainData mySpecialObjectDomainData) {
        this.mySpecialObjectDomainData = mySpecialObjectDomainData ?? throw new ArgumentNullException(ErrorMessageIMySpecialObjectDomainDataIsNull, (Exception)null);
    }
}

E infine, la mia classe multi thread, chiamata da un'app console (app dell'interfaccia della riga di comando)

    public interface IMySpecialObjectThatSpawnsThreads{}

e

public class MySpecialObjectThatSpawnsThreads: IMySpecialObjectThatSpawnsThreads
{
    public const string ErrorMessageIMySpecialObjectManagerIsNull = "IMySpecialObjectManager is null";

    private readonly IMySpecialObjectManager mySpecialObjectManager;

    public MySpecialObjectThatSpawnsThreads(IMySpecialObjectManager mySpecialObjectManager) {
        this.mySpecialObjectManager = mySpecialObjectManager ?? throw new ArgumentNullException(ErrorMessageIMySpecialObjectManagerIsNull, (Exception)null);
    }
}

e l'accumulo di DI. (Di nuovo, questo è per un'applicazione console (interfaccia a riga di comando) ... che mostra un comportamento leggermente diverso rispetto alle app web)

private static IServiceProvider BuildDi(IConfiguration configuration) {
    /* this is being called early inside my command line application ("console application") */

    string defaultConnectionStringValue = string.Empty; /* get this value from configuration */

    ////setup our DI
    IServiceCollection servColl = new ServiceCollection()
        ////.AddLogging(loggingBuilder => loggingBuilder.AddConsole())

        /* THE BELOW TWO ARE THE ONES THAT TRIPPED ME UP.  */
        .AddTransient<IMySpecialObjectDomainData, MySpecialObjectEntityFrameworkDomainDataLayer>()
    .AddTransient<IMySpecialObjectManager, MySpecialObjectManager>()

    /* so the "ServiceLifetime.Transient" below................is what you will find most commonly on the internet search results */
     # if (MY_ORACLE)
        .AddDbContext<ProvisioningDbContext>(options => options.UseOracle(defaultConnectionStringValue), ServiceLifetime.Transient);
     # endif

     # if (MY_SQL_SERVER)
        .AddDbContext<ProvisioningDbContext>(options => options.UseSqlServer(defaultConnectionStringValue), ServiceLifetime.Transient);
     # endif

    servColl.AddSingleton <IMySpecialObjectThatSpawnsThreads,        MySpecialObjectThatSpawnsThreads>();

    ServiceProvider servProv = servColl.BuildServiceProvider();

    return servProv;
}

Quelli che mi hanno sorpreso sono stati il ​​(passaggio a) transitorio per

        .AddTransient<IMySpecialObjectDomainData, MySpecialObjectEntityFrameworkDomainDataLayer>()
    .AddTransient<IMySpecialObjectManager, MySpecialObjectManager>()

Nota, penso che poiché IMySpecialObjectManager veniva iniettato in "MySpecialObjectThatSpawnsThreads", quegli oggetti iniettati dovevano essere Transient per completare la catena.

Il punto è che ....... non era solo il (My) DbContext che aveva bisogno di .Transient ... ma una parte più grande del grafico DI.

Suggerimento per il debug:

Questa linea:

this.entityDbContext = context ?? throw new ArgumentNullException("MyCoolDbContext is null", (Exception)null);

Metti lì il punto di interruzione del debugger. Se il tuo MySpecialObjectThatSpawnsThreads sta facendo un numero N di thread (diciamo 10 thread per esempio) ... e quella linea viene colpita solo una volta ... questo è il tuo problema. Il tuo DbContext sta attraversando i thread.

BONUS:

Suggerirei di leggere questo sotto l'url / articolo (vecchio ma buono) sulle differenze tra app web e app per console

https://mehdi.me/ambient-dbcontext-in-ef6/

Ecco l'intestazione dell'articolo nel caso in cui il collegamento cambi.

GESTIRE DBCONTEXT NEL MODO GIUSTO CON ENTITY FRAMEWORK 6: UNA GUIDA APPROFONDITA Mehdi El Gueddari

Ho riscontrato questo problema con WorkFlowCore https://github.com/danielgerlag/workflow-core

  <ItemGroup>
    <PackageReference Include="WorkflowCore" Version="3.1.5" />
  </ItemGroup>

codice di esempio di seguito .. per aiutare i futuri utenti di Internet

 namespace MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.MySpecialObjectInterview.Workflows
    {
        using System;
        using MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.MySpecialObjectInterview.Constants;
        using MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.MySpecialObjectInterview.Glue;
        using MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.WorkflowSteps;

        using WorkflowCore.Interface;
        using WorkflowCore.Models;

        public class MySpecialObjectInterviewDefaultWorkflow : IWorkflow<MySpecialObjectInterviewPassThroughData>
        {
            public const string WorkFlowId = "MySpecialObjectInterviewWorkflowId";

            public const int WorkFlowVersion = 1;

            public string Id => WorkFlowId;

            public int Version => WorkFlowVersion;

            public void Build(IWorkflowBuilder<MySpecialObjectInterviewPassThroughData> builder)
            {
                builder
                             .StartWith(context =>
                    {
                        Console.WriteLine("Starting workflow...");
                        return ExecutionResult.Next();
                    })

                        /* bunch of other Steps here that were using IMySpecialObjectManager.. here is where my DbContext was getting cross-threaded */


                    .Then(lastContext =>
                    {
                        Console.WriteLine();

                        bool wroteConcreteMsg = false;
                        if (null != lastContext && null != lastContext.Workflow && null != lastContext.Workflow.Data)
                        {
                            MySpecialObjectInterviewPassThroughData castItem = lastContext.Workflow.Data as MySpecialObjectInterviewPassThroughData;
                            if (null != castItem)
                            {
                                Console.WriteLine("MySpecialObjectInterviewDefaultWorkflow complete :)  {0}   -> {1}", castItem.PropertyOne, castItem.PropertyTwo);
                                wroteConcreteMsg = true;
                            }
                        }

                        if (!wroteConcreteMsg)
                        {
                            Console.WriteLine("MySpecialObjectInterviewDefaultWorkflow complete (.Data did not cast)");
                        }

                        return ExecutionResult.Next();
                    }))

                    .OnError(WorkflowCore.Models.WorkflowErrorHandling.Retry, TimeSpan.FromSeconds(60));

            }
        }
    }

e

ICollection<string> workFlowGeneratedIds = new List<string>();
                for (int i = 0; i < 10; i++)
                {
                    MySpecialObjectInterviewPassThroughData currentMySpecialObjectInterviewPassThroughData = new MySpecialObjectInterviewPassThroughData();
                    currentMySpecialObjectInterviewPassThroughData.MySpecialObjectInterviewPassThroughDataSurrogateKey = i;

                    ////  private readonly IWorkflowHost workflowHost;
                    string wfid = await this.workflowHost.StartWorkflow(MySpecialObjectInterviewDefaultWorkflow.WorkFlowId, MySpecialObjectInterviewDefaultWorkflow.WorkFlowVersion, currentMySpecialObjectInterviewPassThroughData);
                    workFlowGeneratedIds.Add(wfid);
                }

0

Ho ricevuto lo stesso messaggio. Ma non ha alcun senso nel mio caso. Il mio problema è che ho utilizzato una proprietà "NotMapped" per errore. Probabilmente in alcuni casi significa solo un errore di sintassi Linq o di classe del modello. Il messaggio di errore sembra fuorviante. Il significato originale di questo messaggio è che non puoi chiamare async sullo stesso dbcontext più di una volta nella stessa richiesta.

[NotMapped]
public int PostId { get; set; }
public virtual Post Post { get; set; }

Puoi controllare questo link per i dettagli, https://www.softwareblogs.com/Posts/Details/5/error-a-second-operation-started-on-this-context-before-a-previous-operation-completed


0

Ho lo stesso problema quando provo a utilizzare FirstOrDefaultAsync() nel metodo asincrono nel codice seguente. E quando ho risolto FirstOrDefault(), il problema è stato risolto!

_context.Issues.Add(issue);
        await _context.SaveChangesAsync();

        int userId = _context.Users
            .Where(u => u.UserName == Options.UserName)
            .FirstOrDefaultAsync()
            .Id;
...

2
Non è affatto correlato a FirstOrDefault () o FirstOrDefaultAsync (), ma riguarda l'utilizzo di dbContext.
sajadre

0

Sono riuscito a ottenere quell'errore passando un IQueryablein un metodo che quindi ha utilizzato quella "lista" IQueryable come parte di un'altra query nello stesso contesto.

public void FirstMethod()
{
    // This is returning an IQueryable
    var stockItems = _dbContext.StockItems
        .Where(st => st.IsSomething);

    SecondMethod(stockItems);
}

public void SecondMethod(IEnumerable<Stock> stockItems)
{
    var grnTrans = _dbContext.InvoiceLines
        .Where(il => stockItems.Contains(il.StockItem))
        .ToList();
}

Per interrompere che accade ho utilizzato l' approccio qui e materializzato tale elenco prima di passarlo il secondo metodo, cambiando la chiamata ad SecondMethodessereSecondMethod(stockItems.ToList()


Questo ha risolto il problema, ma non rallenterà le prestazioni. C'è qualche soluzione alternativa?
Dheeraj Kumar

0

Nel mio caso utilizzo un componente modello in Blazor.

 <BTable ID="Table1" TotalRows="MyList.Count()">

Il problema sta chiamando un metodo (Count) nell'intestazione del componente. Per risolvere il problema l'ho cambiato in questo modo:

int total = MyList.Count();

e più tardi :

<BTable ID="Table1" TotalRows="total">

0

So che questo problema è stato chiesto due anni fa, ma ho appena riscontrato questo problema e la correzione che ho usato ha davvero aiutato.

Se stai eseguendo due query con lo stesso contesto, potresti dover rimuovere il file AsNoTracking. Se usi AsNoTrackingstai creando un nuovo lettore di dati per ogni lettura. Due lettori di dati non possono leggere gli stessi dati.


0

Nel mio caso stavo usando un blocco che non consente l'uso di await e non crea avvisi del compilatore quando non attendi un async.

Il problema:

lock (someLockObject) {
    // do stuff
    context.SaveChangesAsync();
}

// some other code somewhere else doing await context.SaveChangesAsync() shortly after the lock gets the concurrency error

La correzione: attendi l'asincronia all'interno del lucchetto facendolo bloccare con un .Wait ()

lock (someLockObject) {
    // do stuff
    context.SaveChangesAsync().Wait();
}

0

Un altro possibile caso: se utilizzi la connessione diretta, non dimenticare di chiudere if. Avevo bisogno di eseguire query SQL arbitrarie e leggere il risultato. Questa è stata una soluzione rapida, non volevo definire una classe di dati, non impostare una connessione SQL "normale". Quindi ho semplicemente riutilizzato la connessione al database di EFC come var connection = Context.Database.GetDbConnection() as SqlConnection. Assicurati di chiamare connection.Close()prima di farlo Context.SaveChanges().


-2

Se il tuo metodo restituisce qualcosa, puoi risolvere questo errore ponendo .Resultalla fine del lavoro e .Wait()se non restituisce nulla.


-6

Sono appena riuscito a farlo funzionare di nuovo. Non ha molto senso ma ha funzionato:

  1. Rimuovi Hangfire da StartUp (stavo creando il mio lavoro lì)
  2. Eliminato il database degli hangfire
  3. Riavviato il server

Approfondirò ulteriormente in seguito, ma il metodo che ho chiamato con hangfire riceve un DBContext e questa è la possibile causa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.