J'ai donc récemment découvert que vous pouvez forcer Entity Framework à ne pas traduire votre projection en SQL en spécifiant un Func<T, TResult>
à la méthode d'extension .Select()
plutôt qu'une expression. Ceci est utile lorsque vous voulez transformer vos données demandées, mais cette transformation devrait se produire dans votre code plutôt que dans la base de données.Cette méthode d'extension matérialise-t-elle efficacement mon IQueryable?
Par exemple, lorsque vous utilisez un nouveau soutien Enum de EF5 et d'essayer de prévoir que d'une propriété de chaîne dans un DTO, alors que ce serait un échec:
results.Select(r => new Dto { Status = r.Status.ToString() })
cela fonctionnerait:
results.Select(new Func<Record, Dto>(r => new Dto { Status = r.Status.ToString() }));
parce que dans le premier cas (expression), EF ne peut pas comprendre comment traduire Status.ToString() en quelque chose que la base de données SQL pourrait exécuter, mais selon this article Les prédicats Func ne sont pas traduits.
Une fois que j'ai eu ce travail, ce ne fut pas beaucoup d'un saut pour créer la méthode d'extension suivante:
public static IQueryable<T> Materialize<T>(this IQueryable<T> q)
{
return q.Select(new Func<T, T>(t => t)).AsQueryable();
}
Donc, ma question est - ce qu'il ya des pièges que je devrais se méfier lors de l'utilisation de cette ? Y a-t-il un impact sur les performances - soit en injectant cette projection «do-nothing» dans le pipeline de requêtes, soit en empêchant EF d'envoyer la clause .Where()
au serveur et d'envoyer ainsi tous les résultats sur le réseau?
L'intention est d'utiliser encore une méthode .Where()
pour filtrer les résultats sur le serveur, mais d'utiliser .Materialize()
avant .Select()
afin que le fournisseur ne cherche pas à traduire la projection vers SQL Server:
return Context.Record
.Where(r => // Some filter to limit results)
.Materialize()
.Select(r => // Some projection to DTO, etc.);
Ça a l'air bien. 'Where' devrait être envoyé à la base de données. Cependant, pourquoi ne pas simplement utiliser 'ToList()' au lieu de 'Materialize'? –