2010-07-28 4 views
3

Je travaille sur une application ASP.NET MVC qui utilise le modèle de référentiel avec LINQ to SQL comme source de données. Dans mon dépôt j'expose la méthode suivante:Bizande d'expression lambda dans une condition LINQ to SQL

public IEnumerable<T> Find(Expression<Func<T, bool>> where) 
{ 
    return _context.GetTable<T>().Where(where); 
} 

Je suis en mesure d'appeler cela en disant:

repository<User>().Find(u => true); 

Mais si j'essayer de faire (lorsque la recherche est nulle)

repository<User>().Find(u => !string.IsNullOrEmpty(search) ? u.UserName.Contains(search) : true); 

J'obtiens l'erreur:

Value cannot be null. Parameter name: text

I t Je pensais que l'expression lambda exécuterait la même chose puisque la valeur de search est nulle, mais ce n'est clairement pas le cas.

Comment résoudre ce problème?

+0

Pouvez-vous montrer un peu plus de contexte? L'évaluation paresseuse rend LINQ un peu difficile à analyser sans voir comment vous utilisez sa sortie. –

+0

Les paramètres IsNullOrEmpty et Contains s'appellent 'value', donc l'erreur ne vient pas d'eux. – SWeko

+1

@SWeko: 'string.Contains' ne lancerait pas l'exception, l'évaluation de l'analyseur d'expression de l'appel à' string.Contains' pour construire une expression 'LIKE' le ferait. –

Répondre

1

Pour ajouter aux autres réponses, si vous avez à suivre cet idéal, vous pouvez simplement le faire à la place:

repository<User>.Find(u => string.IsNullOrEmpty(search) || 
          u.UserName.Contains(search)); 

Avant d'implémenter aveuglément cela, si vous deviez le faire, s'il vous plaît lire La réponse d'Adam à apprendre des conséquences.

+0

Merci cette solution a travaillé un régal. – nfplee

+0

Je viens de découvrir si je dis: dépôt .Find (u => (string.IsNullOrEmpty (recherche) || u.UserName.Contains (recherche)) && (! Enabled.HasValue || u.Enabled = = enabled.Value)); Je reçois le même problème que précédemment. Grr – nfplee

1

Contient attend une chaîne. Vous devez passer le string.Emtpy.

u.UserName.Contains(search) 

Si vous essayez cela, il va compiler, mais vous obtiendrez une erreur d'exécution:

string str = "Leniel"; 

if (str.Contains(null)) 
{ 
    var num = 1; 
} 

Erreur:

Value cannot be null. 
Parameter name: value 
+1

'string.Contains' n'est pas appelé. L'appel à 'string.Contains' dans l'expression est en train d'être traduit en une expression' LIKE' dans SQL. Cette traduction est ce qui jette l'exception. Notez la différence de noms sur les paramètres ('value' vs.'text') –

3

Parce que c'est une expression, opérateur normal conditionnel logique (n'évaluant pas l'expression fausse) ne s'applique pas automatiquement. Étant donné que l'expression est en cours de traduction dans une expression de requête SQL, LINQ to SQL évalue les paramètres de la condition et, dans ce cas, null. Alors que LIKE null est une syntaxe SQL valide, évidemment, LINQ to SQL n'apprécie pas d'être passé null. Vous devrez construire deux requêtes différentes, une pour un terme nul, une pour un terme non nul.

Soit cela, soit de passer quelque chose comme string.Empty à Contains. Le seul impact ici sera l'impossibilité d'utiliser un index sur la colonne, puisque le serveur effectuera une évaluation conditionnelle répétée sur chaque ligne, forçant un balayage de table. Je conseillerais d'utiliser deux requêtes sans le conditionnel.