LINQ 中的 SQL ISNULL 等价物?

Posted

技术标签:

【中文标题】LINQ 中的 SQL ISNULL 等价物?【英文标题】:Equivalent of SQL ISNULL in LINQ? 【发布时间】:2010-09-29 14:38:56 【问题描述】:

在 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?

【问题讨论】:

您的意思是“aa.Online”吗? “xx”没有在任何地方定义...... 【参考方案1】:

由于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);
            
        

这是 TSQL - 几乎是我们想要的(它不是 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

QED?

【讨论】:

很难保持代表每天超过 200!?!?!是的,对。我检查了System.Data.Linq.SqlClient.SqlMethods,没有任何方法可以确保生成 SQL 的ISNULL,所以我将使用你的代码:-) 用 ISNULL 进行 JOIN 怎么样?同样的事情会起作用吗?有必要吗? 是的,我试过这个并且足够接近并没有削减它。它创建了一个 case 语句,所以当我运行它时,它返回了太多数据。在我删除 case 语句后,sql 恢复正常...抱歉要降级了 正如@dumbledad 所说,没有任何方法可以确保 SQL 的 ISNULL。但由于 CASE 方法的结果和性能与 ISNULL(sqlservercentral.com/Forums/Topic1656650-3412-1.aspx) 相同,因此这是迄今为止最好的答案。【参考方案2】:

您可以使用?? 运算符设置默认值,但首先您必须在dbml 文件中的必填字段(xx.Online) 中将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
        ;

【讨论】:

您不必修改您的 dbml。您可以将 xx.Online 转换为可为空的 int。 Status = ((int?)xx.Online ?? false)【参考方案3】:

我经常遇到序列问题(与离散值相反)。如果我有一个整数序列,并且我想对它们求和,当列表为空时,我将收到错误“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。 (当没有行匹配时,第一个抛出异常)。

【讨论】:

【参考方案4】:

看起来类型是布尔值,因此永远不能为空,默认情况下应该为假。

【讨论】:

如果它来自一个连接,你怎么能让它默认为假? 肯定会默认为false吧?它是一个布尔值并且没有被设置,所以它应该是假的。你在看什么?

以上是关于LINQ 中的 SQL ISNULL 等价物?的主要内容,如果未能解决你的问题,请参考以下文章

sql 中isnull函数的用法

Linq Where() lambda 表达式中的“或”等价物

sql server where 字段 is null 的问题

SQL中 IS NULL 和IS NOT NULL

什么是 linq 等价于 SQL IN 运算符

SQL 到 Linq 实体