代码之家  ›  专栏  ›  技术社区  ›  Stuart

如何处理LINQ子查询中的空值?

  •  3
  • Stuart  · 技术社区  · 16 年前

    我有一个子查询,它从子表返回最近的值。在某些情况下,子查询不返回任何内容。下面的查询在运行时失败,因为推断的memberprice类型为decimal且不可为空。

    简化查询:

    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
    

    在SQL中,子查询将包含top(1),空时返回空值。我如何在Linq中处理这个问题?有没有一种方法可以使memberprice可以为空,或者如果找不到值,将其默认为零(或者更优雅的解决方案)?

    多谢,斯图尔特

    4 回复  |  直到 16 年前
        1
  •  6
  •   Robert Harvey    16 年前

    斯图亚特

    我将数据库中的price字段更改为不允许空值,得到了与您相同的错误:

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

    正如您指出的,当price设置为不允许在数据库中为空时,空合并运算符将不再工作,因为它期望看到可为空的类型decimal:

    decimal?
    

    如果移除空合并运算符并运行不包含价格的测试用例,我将得到:

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

    这是有效的代码。我将子查询结果强制转换为十进制?在应用空合并运算符之前。

    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;
        }
    }
    
        2
  •  3
  •   Robert Harvey    16 年前

    斯图尔特,试试这个:

    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)
    

    空合并运算符将强制memberprice的空值为零。

        3
  •  0
  •   Josh    16 年前

    DefaultifEmpty扩展方法是否执行您要查找的操作?

        4
  •  0
  •   Robert Harvey    16 年前

    斯图亚特

    这就是我让它在我的机器上工作的方法。我为它在C里道歉,我用VB已经太久了。

    注意“select”语句中“new”运算符的用法,以及在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;
        }
    }