LINQ中类似于SQL的ISNULL函数的等效方法是什么?

51

在SQL中,您可以运行ISNULL(null,''),那么在LINQ查询中该怎么做呢?

我在这个查询中有一个连接:

var hht = from x in db.HandheldAssets
        join a in db.HandheldDevInfos on x.AssetID equals a.DevName into DevInfo
        from aa in DevInfo.DefaultIfEmpty()
        select new
        {
        AssetID = x.AssetID,
        Status = xx.Online
        };

但是我有一个非空的位类型列(xx.online),如果它为空,我该如何将其设置为false?


3
你是说 "aa.Online" 吗?"xx" 在任何地方都没有定义过... - Marc Gravell
4个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
59

因为可能为空的对象是 aa,你可以检查 aa == null 吗?

(aa / xx 可能是可以互换的(问题中有笔误);原始问题提到了 xx,但只定义了 aa)

select new {
    AssetID = x.AssetID,
    Status = aa == null ? (bool?)null : aa.Online; // a Nullable<bool>
}

或者,如果你想要默认值为false(而不是null):

select new {
    AssetID = x.AssetID,
    Status = aa == null ? false : aa.Online;
}

更新:针对下降票,我进行了更多的调查... 事实是,这是正确的方法!以下是在Northwind上的一个示例:

        using(var ctx = new DataClasses1DataContext())
        {
            ctx.Log = Console.Out;
            var qry = from boss in ctx.Employees
                      join grunt in ctx.Employees
                          on boss.EmployeeID equals grunt.ReportsTo into tree
                      from tmp in tree.DefaultIfEmpty()
                      select new
                             {
                                 ID = boss.EmployeeID,
                                 Name = tmp == null ? "" : tmp.FirstName
                        };
            foreach(var row in qry)
            {
                Console.WriteLine("{0}: {1}", row.ID, row.Name);
            }
        }

这是 T-SQL 代码,基本符合我们的要求(虽然不是 ISNULL,但足够接近):

SELECT [t0].[EmployeeID] AS [ID],
    (CASE
        WHEN [t2].[test] IS NULL THEN CONVERT(NVarChar(10),@p0)
        ELSE [t2].[FirstName]
     END) AS [Name]
FROM [dbo].[Employees] AS [t0]
LEFT OUTER JOIN (
    SELECT 1 AS [test], [t1].[FirstName], [t1].[ReportsTo]
    FROM [dbo].[Employees] AS [t1]
    ) AS [t2] ON ([t0].[EmployeeID]) = [t2].[ReportsTo]
-- @p0: Input NVarChar (Size = 0; Prec = 0; Scale = 0) []
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.1

证毕?


1
每天保持超过200个回复?!?!不可能吧。 我查看了System.Data.Linq.SqlClient.SqlMethods,发现没有确保生成SQL的ISNULL方法,所以我将使用你的代码 :-) - dumbledad
使用ISNULL进行JOIN怎么样?这样做会起作用吗?是否必要? - Matt
是的,我尝试了这个,但接近并不能解决问题。它创建了一个 case 语句,所以当我运行它时,返回了太多的数据。在我删除了 case 语句之后,SQL 就正常返回了...抱歉,我得将其降级。 - Clarence
正如@dumbledad所说,没有任何方法可以确保SQL的ISNULL。但是由于CASE方法与ISNULL具有相同的结果和性能(https://www.sqlservercentral.com/Forums/Topic1656650-3412-1.aspx),因此这是目前最好的答案。 - Dan Mihai Patrascu

27

您可以使用 ?? 运算符来设置默认值,但首先必须在所需字段 (xx.Online) 中的dbml文件中将Nullable属性设置为true

var hht = from x in db.HandheldAssets
        join a in db.HandheldDevInfos on x.AssetID equals a.DevName into DevInfo
        from aa in DevInfo.DefaultIfEmpty()
        select new
        {
        AssetID = x.AssetID,
        Status = xx.Online ?? false
        };

1
您无需修改dbml。您只需将xx.Online转换为可空整数。 Status = ((int?)xx.Online ?? false) - xr280xr

2
我经常在处理序列(而不是离散值)时遇到问题。如果我有一系列int,并且想要求和,当列表为空时,我会收到错误消息“InvalidOperationException:无法将空值分配给非可空值类型System.Int32的成员。”。 我发现可以通过将序列转换为可空类型来解决此问题。如果可空类型的序列为空,则SUM和其他聚合运算符不会抛出此错误。 因此,例如像这样的东西
MySum = MyTable.Where(x => x.SomeCondtion).Sum(x => x.AnIntegerValue);

变成

MySum = MyTable.Where(x => x.SomeCondtion).Sum(x => (int?) x.AnIntegerValue);
第二个将在没有行与where子句匹配时返回0(第一个在没有行与之匹配时抛出异常)。

0

看起来这个类型是布尔型,因此永远不可能为空,并且默认应该为false。


1
如果它来自于一个连接,你如何使其默认为false? - MartGriff
默认情况下肯定是false吧?它是一个布尔值并且还没有被设置,所以应该是false。你看到了什么? - Ray Booysen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,