C# LINQ到SQL连接生成连接为空的SQL
我不擅长Linq表达式,今天我遇到了一个奇怪的问题,如下面的内部连接语句C# LINQ到SQL连接生成连接为空的SQL,c#,.net,linq,join,C#,.net,Linq,Join,我不擅长Linq表达式,今天我遇到了一个奇怪的问题,如下面的内部连接语句 var orders = (from q in dao.CurrentDBContext.New_OrderForm join d in dao.CurrentDBContext.New_OrderGoodsDetail on q.billNum equals d.billNum select new {
var orders = (from q in dao.CurrentDBContext.New_OrderForm
join d in dao.CurrentDBContext.New_OrderGoodsDetail on q.billNum equals d.billNum
select new
{
q.billNum,
q.orderSource,
q.sourceOddNum
d.PPT
}
当我跟踪linq语句时,我对实体框架将linq语句转换为下面的sql语句感到困惑
SELECT
[Extent1].[billNum] AS [billNum],
[Extent1].[orderSource] AS [orderSource],
[Extent1].[sourceOddNum] AS [sourceOddNum],
[Extent2].[PPT] AS [PPT]
FROM [dbo].[New_OrderForm] AS [Extent1]
INNER JOIN [dbo].[New_OrderGoodsDetail] AS [Extent2]
ON ([Extent1].[billNum] = [Extent2].[billNum]) OR
(([Extent1].[billNum] IS NULL) AND ([Extent2].[billNum] IS NULL))
您知道为什么下面的SQL段会自动追加吗
或([Extent1].[billNum]为空)和([Extent2].[billNum]为空)“
我不期望上面的自动追加,因为它确实降低了SQL性能。有什么建议吗?根据@Giorgi的回答,UseDatabaseNullSemantics
标志将不适用于equals
关键字-只有=
操作数。因此,为了绕过这个问题并确保billN上的连接um不是或
子句的一部分此方法应该有效(与UseDatabaseNullSemantics
标志结合使用):
这将在不使用或的情况下生成连接,似乎Linq翻译q.billNum等于d.billNum
是这样一种方式,即如果q.billNum和d.billNum都为NULL(在SQL中,NULL永远不等于NULL,因此查询中的OR)时,它还包含一个有效匹配项
如果两个字段都不能为NULL,那么使这两个字段都不可为NULL将是最好的解决方案
如果不是这种情况,您还可以尝试在Linq语句中添加where子句,以指定q.billNum和d.billNum都不能为NULL。如果运气好,Linq将认识到不可能为NULL的值
注意:如果您使用Oracle,您应该检查空字符串和NULL(空字符串相当于NULL)。空字符串在SQL Server中作为有效值应该是可以接受的
由于上述情况没有帮助,您可以尝试自己编写查询。如果我没有弄错的话,它将是以下内容(假设var
是示例代码中的列表
——您的查询结果应该与您使用的类相匹配):
StringBuilder查询=新建StringBuilder();
AppendLine(“选择[Extent1].[billNum]作为[billNum],”;
query.AppendLine(“[Extent1].[orderSource]作为[orderSource],”;
AppendLine(“[Extent1].[sourceOddNum]作为[sourceOddNum],”;
query.AppendLine(“[Extent2].[PPT]作为[PPT]”);
AppendLine(“FROM[dbo].[New_OrderForm]AS[Extent1]”;
AppendLine(“内部联接[dbo].[New_ordergoodsdeail]作为[Extent1].[billNum]=[Extent2].[billNum]”上的[Extent2];
List orders=DbContext.Database.SqlQuery(query.ToString()).ToList();
在过去,我使用过类似的解决方法来解决性能问题。如果您使用的是EF6,请尝试设置
context.Configuration.UseDatabaseNullSemantics = true;
它不会为这些列生成空检查
例如,如果UseDatabaseNullSemantics为true,则(操作数1==操作数2)将分别转换为:(操作数1=操作数2),如果UseDatabaseNullSemantics为false,则分别转换为((操作数1=操作数2)和((操作数1为NULL或操作数2为NULL))或((操作数1为NULL)和(操作数2为NULL))
以下是在无法将billNum
列更改为不可为空时可以执行的操作
首先,设置@Giorgi提到的选项
class CurrentDBContext
{
public CurrentDBContext()
{
Configuration.UseDatabaseNullSemantics = true;
// ...
}
}
然后将LINQ查询更改为不使用连接,而是像这样使用简单的where
var orders = (from q in dao.CurrentDBContext.New_OrderForm
from d in dao.CurrentDBContext.New_OrderGoodsDetail
where q.billNum == d.billNum
select ...
结果将是与您所显示的完全相同的SQL查询(withJOIN
!)没有或部分。q.billNum
和d.billNum
的类型是什么?这两种数据类型都是相同的,字符串类型是您的列可以为空的吗?也许q.billNum等于d.billNum
中的等式假设您也希望NULL==NULL
匹配?是的,该列可以为空。可能您没有按要求配置它们。您真的需要它们为空吗?因为这就是为什么EF会附加您所要求的条件的原因。添加where
子句不会删除“extra”或
条件(这需要EF对查询表达式执行“全局”优化)。但是,如果知道billNum
永远不会为NULL
,SQL Server执行计划可能会受益。嗨,山姆,谢谢你的详细回复,现在可能不可行,因为系统处于联机状态,客户不允许我将字段设置为不可为NULL,我已尝试此“var orders=(来自dao.CurrentDBContext.New_OrderForm.Where(p=>p.billNum!=null)中的q,在dao.CurrentDBContext.New_OrderGoodsDetail.Where(p=>p.billNum!=null)中加入d)在q.billNum等于d.billNum'上,也尝试了“或”从dao.CurrentDBContext.New中的q开始,从dao.CurrentDBContext.New\u OrderGoodsDetail.Where(p=>p.billNum==q.billNum&&p.billNum!=null&&q.billNum!=null)“遗憾的是,这两种方法都没有用处。”(谢谢Sam,这也是一个很好的解决方案,但我必须将sql语句从linq代码中切换出来,这样很多linq代码需要更改,因为很多动态条件都附加在业务逻辑代码中,正如您提到的,最好的解决方案是使这两个字段不可为null,我需要说服客户更改它:)实际测试表明,这并不能解决问题(生成了相同的SQL)。文档中的SQL与问题中的SQL也不同。我不确定UseDatabaseNullSemantics
真正的作用是什么。确切地说,我进行了测试,看起来开关没有用(这对我来说非常有效。将标志设置为true将删除SQL或在可空字符串比较上创建。谢谢@Giorgi。刚才我安装了EF 6.1.3,但它仍然不起作用。:(抱歉,我在where子句中使用了它,操作数为=
(根据文档中的示例)。具有
class CurrentDBContext
{
public CurrentDBContext()
{
Configuration.UseDatabaseNullSemantics = true;
// ...
}
}
var orders = (from q in dao.CurrentDBContext.New_OrderForm
from d in dao.CurrentDBContext.New_OrderGoodsDetail
where q.billNum == d.billNum
select ...