Molte eccezioni aggregate nidificate

aggregateexception async-await c# entity-framework-core

Domanda

Lavorando con Entity Framework 7, ho fatto un semplice errore con alcuni linq (usato Skip e ho dimenticato di includere la mia clausola OrderBy).

L'eccezione che è stata generata da questo include un numero di eccezioni aggregate nidificate.

Il codice che genera (e cattura) l'eccezione è:

int[] newIds;
try
{
    newIds = await db.Products
        .Where(p => p.PortalId == portalId)
        .Skip(ids.ProductIds.Count) //Skip the rows already read
        .Take(takeTotal) //get the next block
        .Select(p => p.ProductId)
        .ToArrayAsync();
}
catch (AggregateException ex)
{
    Console.WriteLine(ex.Message);
    newIds = new int[] { };
}

Il codice sopra è in una classe repo chiamata da un controller WebApi Asp.Net 5. Tutti i livelli della chiamata utilizzano asincrono.

Tuttavia l'eccezione aggregata che ho ottenuto da questo era (questo è scaricato nella finestra immediata dal blocco catch mostrato sopra):

System.AggregateException: si sono verificati uno o più errori. ---> System.AggregateException: si sono verificati uno o più errori. ---> System.AggregateException: si sono verificati uno o più errori. ---> System.AggregateException: si sono verificati uno o più errori. ---> System.AggregateException: si sono verificati uno o più errori. ---> System.AggregateException: si sono verificati uno o più errori. ---> System.InvalidOperationException: una query contenente l'operatore Skip deve includere almeno un'operazione OrderBy. in Microsoft.Data.Entity.Relational.Query.Sql.DefaultSqlQueryGenerator.GenerateLimitOffset (SelectExpression selectExpression) in Microsoft.Data.Entity.Relational.Query.Sql.DefaultSqlQueryGenerator.VisitSelectExpression (SelectExpression selectExpression) in Microsoft.Data.Entity.Relational.Query .Expressions.SelectExpression.Accetto (visitatore ExpressionTreeVisitor) in Microsoft.Data.Entity.Relational.Query.Sql.DefaultSqlQueryGenerator.GenerateSql (SelectExpression selectExpression, IDictionary`2 parameterValues) etc etc

Qui l'eccezione effettiva è stata completata da un gruppo di livelli di eccezione aggregata (6 livelli nidificati). Capisco perché sto ricevendo un'eccezione aggregata, ma mi chiedo perché così tanti di loro? Ancora di più dal momento che sto osservando l'eccezione prima che sia tornata al punto di ingresso del controller.

Questo sarebbe il risultato di una serie di livelli di attesa asincrona (non credo di averne fino a 6) o potrebbe essere un problema nell'implementazione dell'EF7?

Attualmente sta usando EF 7 versione 7.0.0-beta4.

Risposta accettata

Come nella pagina di MSDN sulla Task<T> , spiega, tutte le eccezioni generate da un Task sono avvolti in AggregateException prima di essere gettato al codice in attesa. Se utilizzi più livelli di asincrono / attendi e non riesci a catturare questa eccezione al livello più basso possibile, ogni volta che esplode un altro livello, questo verrà riavvolto, portando ad AggregateException all'interno di AggregateException , uno per ogni volta che lo fai. in attesa senza catturare.

Potrebbe anche essere che ogni operazione sia considerata come una sua attività; vale a dire. ogni volta che aggiungi un'altra operazione, il risultato esce da quello precedente e torna al successivo, con ciascuno in attesa del precedente. Guarda:

newIds = await db.Products               // 1
    .Where(p => p.PortalId == portalId)  // 2
    .Skip(ids.ProductIds.Count)          // 3
    .Take(takeTotal)                     // 4
    .Select(p => p.ProductId)            // 5
    .ToArrayAsync();                     // 6

Sei strati di cose, ognuna in attesa del risultato del precedente. Sei livelli di AggregateException . Ora, la tua eccezione è causata dal terzo dei sei, ma dalla natura dell'errore, è probabile che provenga da una parte in cui EF legge tutta la tua query prima di fare qualsiasi cosa, e mentre così facendo viene notato che tu sei " .Skip() un .Skip() senza un matching .OrderBy() .

Come Stephen Cleary mi ha ricordato nei commenti, mentre le cose che await restituiscono Task<T> , fanno anche un certo grado di unwrapping per te, quindi await non si comporta abbastanza come Task<T>.Result , il che significa che l' await dovrebbe eccezione reale senza avvolgerla in AggregateException . Ciò che tutto questo significa è che nella migliore delle ipotesi abbiamo solo metà della risposta qui (che è un po 'imbarazzante, visto che è già stato accettato). Onestamente, ti suggerirei di non accettare questa risposta in modo che gli altri non ignorino la tua domanda e vedere se qualcun altro sa qualcosa che potrebbe colmare le lacune.


Risposta popolare

Non è correlato alla quantità di metodo chiamata in catena. Hai solo bisogno di chiamare ToArrayAsync.

Penso che il problema sia in Rx.NET. Ho inviato una richiesta di pull per risolverlo: https://github.com/aspnet/EntityFramework/issues/2192

https://github.com/Reactive-Extensions/Rx.NET/pull/131/files



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché