2010-08-22 9 views
3

Je développe une petite application utilisant EF 4.0 et POCO.EF 4.0/Comportement bizarre de la méthode FirstOrDefault

Lors du test de mon application, j'ai commencé à m'inquiéter des performances du Data Access Layer. Donc, je tirai SQL Profiler pour voir que lorsque vous essayez de récupérer un enregistrement:

ctx.Orders.Include("OrderItems").FirstOrDefault<Order>(c => c.OrderID == id); 

EF émet une instruction SQL qui récupérerait tous les enregistrements de la table des commandes sur le serveur et en tant que tel retour à la DAL à laquelle L2E choisirait un thay répondre aux critères et le retourner.

Ce comportement peut-il être modifié.

Merci!

Zen

Répondre

9

Essayez celui-ci s'il vous plaît:

ctx.Orders.Include("OrderItems").Where(c => c.OrderID == id).FirstOrDefault(); 


par la façon dont vous n'avez pas besoin de regarder dans SQL Profiler pour voir le SQL généré, vous pouvez le faire à l'intérieur votre code par écrit:

IQueryable<Order> query = ctx.Orders.Include("OrderItems") 
            .Where(c => c.OrderID == id); 
string sql = ((ObjectQuery<Order>)query).ToTraceString(); 


EDIT:
Question: Et si nous avons une fonction comme FindOrders et nous devons passer le prédicat à cette fonction? Réponse: Le code devrait ressembler à:

public List<Order> FindOrders(Expression<Func<Order, bool>> predicate) { 
    using (DBContext ctx = new DBContext()) { 
     return ctx.Orders.Include("OrderItems").Where(predicate).ToList<Order>(); 
    } 
} 

//Calling the function: 
var order = FindOrders(c => c.OrderID == id)[0]; 


Cette fois, si vous vérifiez votre SQL Profiler vous verrez il y a une clause where dans le SQL qui a été soumis à SQL Server.

Explication:
La raison de ce "comportement étrange" est que, fondamentalement, quand vous écrivez Où (c => c.OrderID == id), compilateur C# votre expression jeté lambda dans une expression < Func < TSource, int, bool >> et NOT à un Func < TSource, int, bool>.

MSDN Documentation for Queryable.Where confirme également ceci:

 
public static IQueryable<TSource> Where<TSource>(
    this IQueryable<TSource> source, 
    Expression<Func<TSource, int, bool>> predicate 
) 

Toutefois, si vous passez explicitement un Func < TSource, int, bool >> à la méthode Où alors vous appelez essentiellement Enumerable.Where:

 
public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source, 
    Func<TSource, int, bool> predicate 
) 

Et Comme nous le savons IEnumerable.Where est implémentation "LINQ to Objects" et non "LINQ to Entities" qui signifie que vous atteignez votre appel IEnumerable.Where, la ObjectQuery exéc ery (ctx.Orders.Include ("OrderItems")) et donne les résultats à IEnumerable.Where afin qu'il le filtre pour vous sur le côté client.D'autre part l'appel avec Queryable.Where (ctx.Orders.Include ("OrderItems"). Où (c => c.OrderID == id) .FirstOrDefault()) ne sera pas exécuté jusqu'à ce qu'il atteigne au point que nous appelons la fonction FirstOrDefault() qui signifie le Queryable.Where est ensuite traduit en SQL natif avec le reste de la requête et sera transmis au SQL Server, d'où vous voyez la clause Where sur l'instruction SQL qui certainement est le comportement d'exécution souhaité.

Par ailleurs, ne pas oublier d'importer cet espace de noms à votre fichier de classe:
 
using System.Linq.Expressions; 

+0

Merci Morteza pour votre réponse rapide. Cela fonctionne de toute façon. J'aurais dû formuler ma question autrement. J'ai une fonction comme suit: Liste publique FindOrders (Func prédicat) \t \t { \t \t \t utilisant (DBContext CTX = new DBContext()) \t \t \t { \t \t \t \t Les ctx.Orders de retour .Inclure ("OrderItems"). Où (prédicat) .ToList (); \t \t \t} \t \t} quand j'invoque cette fonction comme var = ordre rep.FindOrders (c => c.OrderID == id) [0] que le Générateur de profils SQL montre une instruction SELECT qui ne contient pas une clause WHERE. Des idées? Merci encore! Zen – UncleZen

+0

Aucun problème. J'ai modifié ma réponse pour résoudre ce problème en transmettant un prédicat à une fonction. S'il vous plaît jeter un oeil et laissez-moi savoir comment celui-ci fonctionne pour vous. –

+0

Merci Morteza, pour votre réponse détaillée. Je ne peux pas attendre pour essayer ceci quand je rentre à la maison. Je vous tiens au courant. Zen – UncleZen