2010-12-15 71 views
11

J'ai une requête de méthode comme ceci:Eviter "L'objet nullable doit avoir une valeur." dans LINQ to Sql

public IList<BusinessObject> GetBusinessObject(Guid? filterId) 
{ 
    using (var db = new L2SDataContext()) 
    { 
     var result = from bo in db.BusinessObjects 
        where (filterId.HasValue) 
           ? bo.Filter == filterId.value 
           : true 
        orderby bo.Name 
        select SqlModelConverters.ConvertBusinessObject(bo); 
     return result.ToList(); 
    } 
} 

Lors de l'exécution, cela jette un System.InvalidOperationException: Nullable object must have a value.

En regardant le Debugger, le problème est ma clause Where: Linq Pour essais SQL pour convertir le tout en SQL, même si filterId est NULL, il essaiera toujours d'accéder à filterId.value.

Je pensais/j'espérais que le compilateur C#/CLR évaluerait cette clause where comme un bloc de code et enverrait seulement l'une des deux branches à Linq To SQL, mais ce n'est pas ainsi que cela fonctionne.

Ma version refactorisé fonctionne, mais pas très élégant:

public IList<BusinessObject> GetBusinessObject(Guid? filterId) 
{ 
    using (var db = new L2SDataContext()) 
    { 
     var temp = from bo in db.BusinessObjects select bo; 
     if(filterId.HasValue) temp = temp.Where(t => t.Filter == filterId.Value); 
     var result = from t in temp 
        orderby t.Name 
        select SqlModelConverters.ConvertBusinessObject(bo); 
     return result.ToList(); 
    } 
} 

Je sais que Lazy-évaluation fera en sorte qu'une seule requête est vraiment envoyé, mais ayant cet objet temp il n'y a pas que super vraiment.

Répondre

16

Avez-vous essayé:

where filterId == null || t.Filter == filterId 
+1

Oh wow, qui fonctionne parfaitement! Il me sauve de l'utilisation de l'opérateur tertiaire légèrement illisible, et il résout l'exception réelle qui est causée en accédant inutilement à filterId.Value au lieu de juste filterId. –

1

Votre solution est tout à fait correct. Vous essayez effectivement de créer une requête de manière dynamique, en fonction de votre entrée de fonction. C'est une bonne idée d'omettre la clause where au lieu de fournir WHERE TRUE de toute façon. Si j'écrivais cette requête, j'irais moi-même avec votre version fixe.

Ce n'est pas aussi jolie que l'utilisation des mots clés du langage, mais il est toujours la bonne façon d'aborder la question à mon avis.