我想执行像这样的查询
var result = from entry in table
where entry.something == null
select entry;
并生成IS NULL
。
编辑: 在前两个答案之后,我觉得有必要澄清我正在使用实体框架 而不是Linq to SQL。 object.Equals()方法似乎不适用于EF。
编辑2:
以上查询按预期工作。它正确生成IS NULL
。我的生产代码是
value = null;
var result = from entry in table
where entry.something == value
select entry;
,生成的SQL为something = @p; @p = NULL
。似乎EF正确地转换了常量表达式,但是如果涉及变量,它就像正常比较一样处理它。实际上是有道理的。我将结束这个问题
答案 0 :(得分:123)
Linq-to-SQL的解决方法:
var result = from entry in table
where entry.something.Equals(value)
select entry;
Linq-to-Entities的解决方法(哎哟!):
var result = from entry in table
where (value == null ? entry.something == null : entry.something == value)
select entry;
这是一个令人讨厌的虫子,已经咬过我好几次了。 如果此错误也影响了您,请访问bug report on UserVoice并告知Microsoft此错误也会对您造成影响。
修改: This bug is being fixed in EF 4.5!谢谢大家提出这个错误!
为了向后兼容,它将选择加入 - 您需要手动启用设置才能使entry == value
正常工作。还没有关于这个设置是什么的消息。请继续关注!
编辑2:根据EF小组的this post,此问题已在EF6中修复!哇噢!强>
我们更改了EF6的默认行为以补偿三值逻辑。
这意味着现有代码依赖于旧行为(null != null
,但仅在与变量进行比较时)将需要更改为不依赖于该行为,或者将UseCSharpNullComparisonBehavior
设置为false以使用旧的破坏行为。
答案 1 :(得分:17)
从Entity Framework 5.0开始,您可以使用以下代码来解决您的问题:
public abstract class YourContext : DbContext
{
public YourContext()
{
(this as IObjectContextAdapter).ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior = true;
}
}
这可以解决您的问题,因为实体Framerwork将使用'C#like'null比较。
答案 2 :(得分:16)
有一个稍微简单的解决方法适用于LINQ to Entities:
var result = from entry in table
where entry.something == value || (value == null && entry.something == null)
select entry;
这很有用,因为AZ注意到,LINQ to Entities特殊情况x == null(即与null常量的相等比较)并将其转换为x IS NULL。
我们正在考虑改变这种行为,以便在等式的两边都可以为空的情况下自动引入补偿比较。但是有一些挑战:
无论如何,我们是否开始研究这将取决于客户分配给它的相对优先级。如果您关心这个问题,我建议您在我们的新功能建议网站上投票:https://data.uservoice.com。
答案 3 :(得分:8)
如果是可以为空的类型,可以尝试使用HasValue属性吗?
var result = from entry in table
where !entry.something.HasValue
select entry;
这里没有任何EF可以测试......只是一个建议=)
答案 4 :(得分:5)
var result = from entry in table
where entry.something.Equals(null)
select entry;
MSDN参考:LINQ to SQL: .NET Language-Integrated Query for Relational Data
答案 5 :(得分:5)
使用Object.Equals()
代替==
检查此reference
答案 6 :(得分:3)
指出所有实体框架< 6.0建议产生一些尴尬的SQL。请参阅第二个示例" clean"固定。
// comparing against this...
Foo item = ...
return DataModel.Foos.FirstOrDefault(o =>
o.ProductID == item.ProductID
// ridiculous < EF 4.5 nullable comparison workaround http://stackoverflow.com/a/2541042/1037948
&& item.ProductStyleID.HasValue ? o.ProductStyleID == item.ProductStyleID : o.ProductStyleID == null
&& item.MountingID.HasValue ? o.MountingID == item.MountingID : o.MountingID == null
&& item.FrameID.HasValue ? o.FrameID == item.FrameID : o.FrameID == null
&& o.Width == w
&& o.Height == h
);
导致SQL如:
SELECT TOP (1) [Extent1].[ID] AS [ID],
[Extent1].[Name] AS [Name],
[Extent1].[DisplayName] AS [DisplayName],
[Extent1].[ProductID] AS [ProductID],
[Extent1].[ProductStyleID] AS [ProductStyleID],
[Extent1].[MountingID] AS [MountingID],
[Extent1].[Width] AS [Width],
[Extent1].[Height] AS [Height],
[Extent1].[FrameID] AS [FrameID],
FROM [dbo].[Foos] AS [Extent1]
WHERE (CASE
WHEN (([Extent1].[ProductID] = 1 /* @p__linq__0 */)
AND (NULL /* @p__linq__1 */ IS NOT NULL)) THEN
CASE
WHEN ([Extent1].[ProductStyleID] = NULL /* @p__linq__2 */) THEN cast(1 as bit)
WHEN ([Extent1].[ProductStyleID] <> NULL /* @p__linq__2 */) THEN cast(0 as bit)
END
WHEN (([Extent1].[ProductStyleID] IS NULL)
AND (2 /* @p__linq__3 */ IS NOT NULL)) THEN
CASE
WHEN ([Extent1].[MountingID] = 2 /* @p__linq__4 */) THEN cast(1 as bit)
WHEN ([Extent1].[MountingID] <> 2 /* @p__linq__4 */) THEN cast(0 as bit)
END
WHEN (([Extent1].[MountingID] IS NULL)
AND (NULL /* @p__linq__5 */ IS NOT NULL)) THEN
CASE
WHEN ([Extent1].[FrameID] = NULL /* @p__linq__6 */) THEN cast(1 as bit)
WHEN ([Extent1].[FrameID] <> NULL /* @p__linq__6 */) THEN cast(0 as bit)
END
WHEN (([Extent1].[FrameID] IS NULL)
AND ([Extent1].[Width] = 20 /* @p__linq__7 */)
AND ([Extent1].[Height] = 16 /* @p__linq__8 */)) THEN cast(1 as bit)
WHEN (NOT (([Extent1].[FrameID] IS NULL)
AND ([Extent1].[Width] = 20 /* @p__linq__7 */)
AND ([Extent1].[Height] = 16 /* @p__linq__8 */))) THEN cast(0 as bit)
END) = 1
如果要生成更清晰的SQL,请执行以下操作:
// outrageous < EF 4.5 nullable comparison workaround http://stackoverflow.com/a/2541042/1037948
Expression<Func<Foo, bool>> filterProductStyle, filterMounting, filterFrame;
if(item.ProductStyleID.HasValue) filterProductStyle = o => o.ProductStyleID == item.ProductStyleID;
else filterProductStyle = o => o.ProductStyleID == null;
if (item.MountingID.HasValue) filterMounting = o => o.MountingID == item.MountingID;
else filterMounting = o => o.MountingID == null;
if (item.FrameID.HasValue) filterFrame = o => o.FrameID == item.FrameID;
else filterFrame = o => o.FrameID == null;
return DataModel.Foos.Where(o =>
o.ProductID == item.ProductID
&& o.Width == w
&& o.Height == h
)
// continue the outrageous workaround for proper sql
.Where(filterProductStyle)
.Where(filterMounting)
.Where(filterFrame)
.FirstOrDefault()
;
首先产生你想要的东西:
SELECT TOP (1) [Extent1].[ID] AS [ID],
[Extent1].[Name] AS [Name],
[Extent1].[DisplayName] AS [DisplayName],
[Extent1].[ProductID] AS [ProductID],
[Extent1].[ProductStyleID] AS [ProductStyleID],
[Extent1].[MountingID] AS [MountingID],
[Extent1].[Width] AS [Width],
[Extent1].[Height] AS [Height],
[Extent1].[FrameID] AS [FrameID],
FROM [dbo].[Foos] AS [Extent1]
WHERE ([Extent1].[ProductID] = 1 /* @p__linq__0 */)
AND ([Extent1].[Width] = 16 /* @p__linq__1 */)
AND ([Extent1].[Height] = 20 /* @p__linq__2 */)
AND ([Extent1].[ProductStyleID] IS NULL)
AND ([Extent1].[MountingID] = 2 /* @p__linq__3 */)
AND ([Extent1].[FrameID] IS NULL)
答案 7 :(得分:2)
var result = from entry in table
where entry.something == null
select entry;
上述查询按预期工作。它正确生成IS NULL。我的生产代码是
var value = null;
var result = from entry in table
where entry.something == value
select entry;
生成的SQL是= @p; @p = NULL。似乎EF正确地转换了常量表达式,但是如果涉及变量,它就像正常比较一样处理它。实际上是有道理的。
答案 8 :(得分:1)
看来Linq2Sql也有这个“问题”。由于ANSI NULL是ON还是OFF,似乎存在这种行为的正当理由,但令人难以理解为什么直的“== null”实际上会按预期工作。
答案 9 :(得分:1)
个人而言,我更喜欢:
var result = from entry in table
where (entry.something??0)==(value??0)
select entry;
在
var result = from entry in table
where (value == null ? entry.something == null : entry.something == value)
select entry;
因为它可以防止重复 - 虽然这在数学上并不准确,但它适合大多数情况。
答案 10 :(得分:0)
我无法对divega的帖子发表评论,但在此处介绍的不同解决方案中,divega的解决方案可以产生最好的SQL。表现明智和长度明智。我刚刚查看了SQL Server Profiler并查看了执行计划(“SET STATISTICS PROFILE ON”)。
答案 11 :(得分:0)
不幸的是,在Entity Framework 5 DbContext中,问题仍然没有解决。
我使用了这种解决方法(适用于MSSQL 2012,但在未来的MSSQL版本中可能不推荐使用ANSI NULLS设置)。
public class Context : DbContext
{
public Context()
: base("name=Context")
{
this.Database.Connection.StateChange += Connection_StateChange;
}
void Connection_StateChange(object sender, System.Data.StateChangeEventArgs e)
{
// Set ANSI_NULLS OFF when any connection is opened. This is needed because of a bug in Entity Framework
// that is not fixed in EF 5 when using DbContext.
if (e.CurrentState == System.Data.ConnectionState.Open)
{
var connection = (System.Data.Common.DbConnection)sender;
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = "SET ANSI_NULLS OFF";
cmd.ExecuteNonQuery();
}
}
}
}
应该注意的是,这是一个肮脏的解决方法,但它可以非常快速地实施,适用于所有查询。
答案 12 :(得分:0)
如果你喜欢像我一样使用方法(lambda)语法,你可以这样做:
var result = new TableName();
using(var db = new EFObjectContext)
{
var query = db.TableName;
query = value1 == null
? query.Where(tbl => tbl.entry1 == null)
: query.Where(tbl => tbl.entry1 == value1);
query = value2 == null
? query.Where(tbl => tbl.entry2 == null)
: query.Where(tbl => tbl.entry2 == value2);
result = query
.Select(tbl => tbl)
.FirstOrDefault();
// Inspect the value of the trace variable below to see the sql generated by EF
var trace = ((ObjectQuery<REF_EQUIPMENT>) query).ToTraceString();
}
return result;
答案 13 :(得分:-1)
var result = from entry in table
where entry.something == value||entry.something == null
select entry;
使用