web-dev-qa-db-fra.com

L'expression LINQ n'a pas pu être traduite et sera évaluée localement

Je reçois cet AVERTISSEMENT dans EntityFramework Core, qu'est-ce qui ne va pas?

J'ai déjà défini MSSQL Datebase sur sensible à la casse.

Latin1_General_100_CS_AS

var test = await _context.Students
                .FirstOrDefaultAsync(m => m.LastName.Equals("ALEXANDER", StringComparison.InvariantCultureIgnoreCase));

Microsoft.EntityFrameworkCore.Query: Avertissement: l'expression LINQ "où [m] .LastName.Equals (" ALEXANDER ", InvariantCultureIgnoreCase)" n'a pas pu être traduite et sera évaluée localement.

3
Aorus1337

Vous devez être conscient de la différence entre IEnumerable et Iqueryable.

Un objet IEnumerable représente une séquence d'objets. Il contient tout pour énumérer cette séquence: vous pouvez demander le premier élément de la séquence, et une fois que vous avez un élément, vous pouvez demander le suivant, tant qu'il y en a un suivant.

Un objet IQueryable ressemble à un IEnumerable, cependant, il ne représente pas une séquence énumérable, il représente le potentiel d'obtenir une séquence IEnumerable.

L'objet IQueryable contient un Expression et un Provider. Expression est une description générique exprimant ce qui doit être interrogé. Le Provider sait qui exécutera la requête (généralement un système de gestion de base de données) et quelle langue est utilisée pour communiquer avec ce SGBD (généralement SQL).

Si vous commencez à énumérer un IQueryable, soit en utilisant explicitement GetEnumerator et MoveNext, soit implicitement en appelant foreach, ToList, Max, FirstOrDefault, etc., qui seront profondément appelés Call GetEnumerator et MoveNext, l'expression est envoyé au fournisseur, qui le traduira en SQL et récupérera les données du SGBD. Les données extraites sont renvoyées sous la forme d'un IEnumerable, dont GetEnumerator et MoveNext sont appelés.

La requête n'est donc pas exécutée avant d'appeler GetEnumerator et MoveNext.

Qu'est-ce que cela a à voir avec ma question?

Le framework d'entité ne peut convertir que les classes et méthodes en SQL qu'il connaît. Entity Framework ne connaît pas vos propres fonctions. En fait, il existe plusieurs fonctions LINQ qui ne sont pas prises en charge par le framework d'entité. Voir Méthodes LINQ prises en charge et non prises en charge

L'une des méthodes non prises en charge est String.Equals(string, StringComparison). Si vous utilisez cette fonction, le compilateur ne peut pas se plaindre, vous verrez cette erreur au moment de l'exécution. Il vous indique que les données seront d'abord récupérées avant l'appel de la fonction. Cela pourrait conduire à un comportement inefficace.

Votre instruction LINQ est égale à (laissez de côté l'attente asynchrone, ne fait pas partie du problème)

var test = dbContext.Students
    .Where(student => student.LastName.Equals("ALEXANDER", StringComparison.InvariantCultureIgnoreCase))
    .FirstOrDefault();

Comme Equals ne peut pas être utilisé, l'avertissement indique que les données sont récupérées localement avant l'exécution de Where. Il se peut donc que plusieurs éléments qui ne passeront pas le Where soient transférés du SGBD vers votre processus local.

Si votre base de données peut ignorer la sensibilité à la casse, envisagez de changer votre code en:

var test = dbContext.Students
    .Where(student => student.LastName == "ALEXANDER")
    .FirstOrDefault();

Cela se traduira par une instruction SQL similaire à:

SELECT TOP 1 * from myDatabase.Students where LastName = "ALEXANDER"

(Je ne sais pas si c'est du SQL correct, puisque j'utilise le framework d'entité, mon SQL est un peu rouillé. Je suppose que vous obtiendrez l'essentiel)

5
Harald Coppoolse

EntityFramework ne peut pas traduire Equals("ALEXANDER", StringComparison.InvariantCultureIgnoreCase) en SQL, donc à la place il chargera toute la table Students en mémoire et recherchera ensuite la première entrée qui satisfait à l'égalité.

1
Elias N