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 等价物?的主要内容,如果未能解决你的问题,请参考以下文章