Après la mise à niveau de mon projet de (dotnet core 2/ef core 2) vers (dotnet core 3/ef core 3) presque toutes mes requêtes LINQ de structure d'entité sont cassées. alors que j'ai déjà lu this il est encore difficile de savoir quoi faire.
Voici quelques exemples qui me posent problème:
var league = await dbContext.League.LastAsync();
Alors que ce code fonctionnait très bien dans ef core 2, il lève une exception dans ef core 3. La seule solution de contournement que j'ai pu trouver à ce sujet était le code suivant qui n'est toujours pas ce que je veux car il n'est pas asynchrone comme avant.
var league = dbContext.League.AsEnumerable().Last();
Un autre exemple qui lève la même exception est le code suivant:
var user = await dbContext.User.FirstOrDefaultAsync(u =>
u.UserId == userId && string.Equals(u.Token, token, StringComparison.InvariantCulture));
Je peux toujours utiliser AsEnumerable () mais la version asynchrone de FirstOrDefault n'y est pas disponible, ce n'est donc pas une option. quelqu'un peut-il me guider avec ça?
[~ # ~] modifier [~ # ~]
Voici l'exception:
System.InvalidOperationException: The LINQ expression 'Last<League>(DbSet<League>)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.Microsoft.com/fwlink/?linkid=2101038 for more information.
La réponse à votre question va être très détaillée car elle correspond à des changements différents survenus dans EF Core 3.0; Alors, considérons-en juste une petite partie.
Comme vous l'avez mentionné dans votre question, Microsoft a une description quelque peu confuse des modifications apportées à la version 3.0 dans ce message .
La première partie de l'article ci-dessus est: ' Les requêtes LINQ ne sont plus évaluées sur le client'. Cela dit, avant que les développeurs n'écrivent des requêtes qui comportent deux parties; Une partie était une requête sur la base de données et une autre partie était une expression qui n'était connue que pour le code client. Dans cette situation client evaluation of potentially expensive expressions only triggered a warning
. Mais dans la nouvelle version, EF core permet uniquement au dernier appel Select () d'être évalué sur le client et lève une exception lorsqu'il existe des expressions qui ne peuvent pas être converties en SQL ou en paramètre.
Pour clarifier cette partie, jetons un coup d'œil à un exemple décrit par Diego Vega dans son article de blog d'annonce EF Core 3. .
Basculer explicitement vers l'évaluation client : si votre requête filtre les données en fonction d'une expression qui ne peut pas être traduite en SQL, vous devrez peut-être basculer explicitement vers l'évaluation client en l'insertion d'un appel à AsEnumerable (), AsAsyncEnumerable (), ToList () ou ToListAsync () au milieu de la requête. Par exemple, la requête suivante ne fonctionnera plus dans EF Core 3.0 car l'un des prédicats de la clause where nécessite une évaluation client:
var specialCustomers = context.Customers
.Where(c => c.Name.StartsWith(n) && IsSpecialCustomer(c));
Mais si vous savez qu'il est raisonnable de traiter une partie du filtre sur le client, vous pouvez réécrire la requête comme suit:
var specialCustomers = context.Customers
.Where(c => c.Name.StartsWith(n))
.AsEnumerable() // Start using LINQ to Objects (switch to client evaluation)
.Where(c => IsSpecialCustomer(c));
Dans l'exemple ci-dessus, IsSpecialCustomer(c)
est une méthode qui ne peut pas être convertie en SQL car c'est une méthode C # qui n'est disponible que dans le code client. Les développeurs doivent donc soit réécrire la requête sous une forme qui peut être traduite, soit interroger la base de données, puis évaluer les résultats de la base de données pour le client à l'aide de .AsEnumerable()
puis il est possible de filtrer les résultats en fonction de IsSpecialCustomer(c)
valeur retournée. C'est pourquoi vous pouvez toujours accéder à AsEnumerable()
dans votre code.
Voyons maintenant pourquoi la méthode FirstOrDefaultAsync()
n'est pas disponible?
Eh bien, il y a deux raisons à l'origine de cette situation.
J'ai déjà répondu à la première raison: le code pour détecter le SQL non composable a été supprimé dans la version 3.0.
Et le second est: le pipeline de requêtes ne comprend pas les opérateurs interrogables asynchrones dans l'arborescence d'expression (par exemple: lorsque vous essayez d'y accéder sur EF.CompileQuery()
).
Dans l'ensemble, il y a quelques articles intéressants que vous pouvez lire:
40 briser les mauvais changements dans ef core
Annonce de l'entité framework core 3.0 preview 9 et entity framework 6.3 preview 9
utilisez OrderByDesc()
pour certaines propriétés puis FirstAsync()
. ( https://github.com/aspnet/EntityFrameworkCore/issues/18211 )
la comparaison invariante n'est pas traduite, a probablement été évaluée précédemment par le client. Selon le paramètre de classement de votre base de données, vous pouvez probablement faire un égal normal ici.
L'appel de AsEnumerable()
sur votre DbSet
sans aucun filtre entraînera le retrait de toutes les données localement, pas quelque chose que vous voulez faire en production. Essayez de réécrire ci-dessus et surveillez le SQL généré pour vous assurer d'obtenir des requêtes performantes.