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 等价物?的主要内容,如果未能解决你的问题,请参考以下文章
Linq Where() lambda 表达式中的“或”等价物