2016-12-07 3 views
3

Je suis un débutant chez Linq et un vrai débutant avec des arbres d'expression.Linq dynamique où clause throws OutOfMemoryException

J'ai une routine d'expression générique qui construit simple Linq clause where que j'ai trouvé à:
https://www.simple-talk.com/dotnet/net-framework/dynamic-linq-queries-with-expression-trees/

public Func<TSource,bool> SimpleFilter<TSource> (string property, object value) 
{ 
    var type = typeof(TSource); 
    var pe = Expression.Parameter(type, "p"); 
    var propertyReference = Expression.Property(pe,property); 
    var constantReference = Expression.Constant(value); 
    var ret = Expression.Lambda<Func<TSource, bool>> 
     (Expression.Equal(propertyReference, constantReference), new[] { pe }); 
    return ret.Compile(); 
} 

Quand j'appelle la fonction comme SimpleFilter("JobCustomerID", 449152) il rendements (p => p.JobCustomerId == 449152) ce qui est correct.

Si je place manuellement ce critère dans ma déclaration Linq, j'obtiens le bon retour.

var jj = db.VW_Job_List.Where((p => p.JobCustomerId == 449152)); 

Cependant lorsqu'il est appelé par l'intermédiaire de la fonction de filtre, la Linq déclenche une OutOfMemoryException. Il est appelé dans ma demande que:

var jj = db.VW_Job_List.Where(SimpleFilter<VW_Job_List>("JobCustomerID", 449152)); 

Si j'appelle la fonction avec un critère de texte, il retourne correctement:

var jj = db.VW_Job_List.Where(SimpleFilter<VW_Job_List>("CompanyCode", "LCS")); 

Y at-il quelque chose de spécifique sur l'utilisation d'une variable entière qui doit être logé? Est-ce que j'ai quelque chose codé incorrectement? Toutes les pensées ou les idées seront appréciées.

+0

Vous base de données requête? Si oui, combien de lignes y a-t-il dans la table VW_Job_List? – Evk

Répondre

3

Les deux appels

var jj = db.VW_Job_List.Where((p => p.JobCustomerId == 449152)); 

et

var jj = db.VW_Job_List.Where(SimpleFilter<VW_Job_List>("JobCustomerID", 449152)); 

ne sont pas équivalents. Le premier résout à Queryable.Where, d'où le filtre est appliqué à l'intérieur de la base de données, tandis que le second - à Enumerable.Where, provoquant ainsi le chargement de la table entière en mémoire et en appliquant le filtre là.

Le problème est que le type de retour de votre SimpleFilter est Func<TSource, bool>. Afin de les rendre équivalents, il devrait être Expression<Func<TSource, bool>>. Notez que même si elles ont la même apparence visuelle, il existe une énorme différence entre l'expression lambda et le délégué lambda en raison de la résolution de surcharge différente appliquée à IQueryable<T>.

Ainsi, changer la méthode comme celui-ci et essayez à nouveau:

public Expression<Func<TSource,bool>> SimpleFilter<TSource> (string property, object value) 
{ 
    var type = typeof(TSource); 
    var pe = Expression.Parameter(type, "p"); 
    var propertyReference = Expression.Property(pe,property); 
    var constantReference = Expression.Constant(value); 
    var ret = Expression.Lambda<Func<TSource, bool>> 
     (Expression.Equal(propertyReference, constantReference), new[] { pe }); 
    return ret; // No .Compile() 
} 
+0

Hummm intéressant. Je n'ai jamais pensé à la différence entre utiliser 'Expression <...>' et ne pas l'utiliser avec EF –

+0

Cela peut sauver mes applications web de la dégradation des performances. Je vous remercie. –