简体   繁体   English

如何在LINQ子查询中处理Null?

[英]How to handle Null in LINQ Subquery?

I've got a subquery that returns the most recent value from a child table. 我有一个子查询,它返回子表中的最新值。 In some cases the subquery returns nothing. 在某些情况下,子查询不返回任何内容。 The query below fails at runtime because the inferred type of MemberPrice is decimal and is not nullable. 下面的查询在运行时失败,因为MemberPrice的推断类型是十进制且不可为空。

Simplified query: 简化查询:

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

In SQL, the subquery would contain Top (1) and would return Null when empty. 在SQL中,子查询将包含Top(1)并在空时返回Null。 How can I handle this in LINQ? 我怎样才能在LINQ中处理这个问题? Is there a way to make MemberPrice nullable or default the value to zero if not found (or a more elegant solution)? 有没有办法让MemberPrice可以为空,或者如果找不到则将值默认为零(或更优雅的解决方案)?

Many thanks, Stuart 非常感谢,斯图尔特

Stuart, 斯图尔特,

I changed my Price field in the database to not allow nulls, and I got the same errror you did: 我将数据库中的Price字段更改为不允许空值,我得到了同样的错误:

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

As you pointed out, when Price is set to not allow nulls in the database, the null coalescing operator no longer works because it is expecting to see a nullable type decimal: 正如您所指出的,当Price设置为不允许数据库中的空值时,空合并运算符不再起作用,因为它期望看到可为空的类型十进制:

decimal?

If I remove the null coalescing operator and run the test case that doesn't contain a price, I get: 如果我删除空合并运算符并运行不包含价格的测试用例,我得到:

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

Here is the code that works. 这是有效的代码。 I cast the subquery result to decimal? 我将子查询结果转换为十进制? before applying the null coalescing operator. 在应用空合并运算符之前。

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;
    }
}

Stuart, try this: 斯图尔特,试试这个:

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)

The null coalescing operator will coerce the null value to zero for MemberPrice. null合并运算符会将MemberPrice的null值强制为零。

DefaultIfEmpty扩展方法是否可以满足您的需求?

Stuart, 斯图尔特,

This is how I got it to work on my machine. 这就是我在机器上工作的方式。 I apologize for it being in c#; 我为它在c#中道歉; it's been too long since I've used VB. 自从我使用VB以来已经太久了。

Note the use of the "new" operator in the "select" statement, and the use of the null coalescing operator after the FirstOrDefault(). 注意在“select”语句中使用“new”运算符,以及在FirstOrDefault()之后使用null coalescing运算符。

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;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM