2009-05-24 9 views
3

J'ai une sous-requête qui retourne la valeur la plus récente d'une table enfant. Dans certains cas, la sous-requête ne renvoie rien. La requête ci-dessous échoue à l'exécution car le type inféré de MemberPrice est décimal et n'est pas nullable.Comment gérer Null dans la sous-requête LINQ?

requête simplifiée:

Dim q = From s In dc.STOCKs _ 
     Select s.ID, MemberPrice = _ 
      (From mp In dc.STOCKPRICEs Where mp.NUMBER = s.NUMBER _ 
      Order By dc.date Descending _ 
      Select mp.PRICE).FirstOrDefault 

Dans SQL, la sous-requête contiendrait Top (1) et renvoyait nul quand il est vide. Comment puis-je gérer cela dans LINQ? Existe-t-il un moyen de rendre null MemberPrice null ou par défaut la valeur à zéro si elle n'est pas trouvée (ou une solution plus élégante)?

Un grand merci, Stuart

+0

Pouvez-vous définir ce que vous voulez dire par échec? FirstOrDefault doit renvoyer Nothing si la sous-requête est vide et que, par conséquent, MemberPrice doit être 0 dans ce cas. – JaredPar

+0

Je reçois une System.InvalidOperationException {"La valeur null ne peut pas être assignée à un membre avec le type System.Decimal qui est un type de valeur non nullable."}. Je m'attendais aussi à ce qu'il retourne 0 si nul, donc je dois manquer quelque chose. – Stuart

+0

Quel est le type de mp.PRICE? – JaredPar

Répondre

6

Stuart,

j'ai changé mon champ de prix dans la base de données de ne pas permettre nulls, et je me suis même errror que vous avez fait:

"Operator '??' cannot be applied to operands of type 'decimal' and 'int'". 

Comme vous l'avez dit, lorsque le prix est défini pour ne pas autoriser les valeurs NULL dans la base de données, l'opérateur de fusion null ne fonctionne plus car il s'attend à voir un type décimal NULL:

decimal? 

Si je supprime l'opérateur coalescent null et exécutez le test qui ne contient pas de prix, je reçois:

"The null value cannot be assigned to a member with type System.Decimal which is a non-nullable value type.." 

Voici le code qui fonctionne. Je lance le résultat de la sous-requête en décimal? avant d'appliquer l'opérateur de coalescence nulle.

public class Class1 
{ 

    DataClasses1DataContext dc = new DataClasses1DataContext(); 

    public decimal test(int stockID) 
    { 

     var q = from s in dc.Stocks 
       where s.StockID == stockID 
       select new 
       { 
        StockID = s.StockID, 
        memberPrice = ((decimal?)(from mp in dc.StockPrices 
            where mp.StockID == s.StockID 
            select mp.Price).FirstOrDefault()) ?? 0 
       }; 

     return q.FirstOrDefault().memberPrice; 
    } 
} 
+0

Robert, merci beaucoup d'aller au-delà pour résoudre ce problème. – Stuart

3

Stuart, essayez ceci:

Dim q = From s In dc.STOCKs _ 
    Select s.ID, MemberPrice = _ 
     if((From mp In dc.STOCKPRICEs Where mp.NUMBER = s.NUMBER _ 
     Order By dc.date Descending _ 
     Select mp.PRICE).FirstOrDefault),0) 

L'opérateur coalescent null forcera la valeur nulle à zéro pour MemberPrice.

+0

L'opérateur de coalescence nulle?n'existe pas dans vb.net –

+1

Oui, c'est le cas: La fonction If. Comme dans If (possibleNullValue, valueIfNull) –

+0

@Robert, j'ai édité l'exemple de code pour utiliser la version VB.Net de l'opérateur de coalescence. – JaredPar

0

La méthode d'extension DefaultIfEmpty fait-elle ce que vous cherchez?

+0

Je l'ai utilisé pour des jointures externes plates, mais je n'ai pas pu déterminer comment faire pour ne rien assigner au type de valeur décimale mp.Price. Avez-vous des idées sur la syntaxe que je pourrais essayer? – Stuart

0

Stuart,

Voilà comment je l'ai eu à travailler sur ma machine. Je suis désolé de l'être en C#; ça fait trop longtemps que j'ai utilisé VB.

Notez l'utilisation de l'opérateur "new" dans l'instruction "select" et l'utilisation de l'opérateur de fusion null après le FirstOrDefault().

public class Class1 
{ 

    DataClasses1DataContext dc = new DataClasses1DataContext(); 

    public decimal MemberPrice(int stockID) 
    { 

     var q = from s in dc.Stocks 
       where s.StockID == stockID 
       select new 
       { 
        StockID = s.StockID, 
        memberPrice = (from mp in dc.StockPrices 
            where mp.StockID == s.StockID 
            select mp.Price).FirstOrDefault() ?? 0 
       }; 

     return q.FirstOrDefault().memberPrice; 
    } 
} 
+0

Je reçois la même erreur de compilateur avec ce code en C# parce que memberPrice est déduit en tant que décimal (vs Nullable ). L'erreur est "Operator '??' ne peut pas être appliqué aux opérandes de type 'decimal' et 'int' ". Quel est le type de prix sur votre machine? – Stuart

+0

Le type de prix sur ma machine est Decimal (18,0) Allow Nulls. –

Questions connexes