我一直在试验LinqPad中的查询。我们有一个表Lot
,其中包含Side char(1)
列。当我将linq写入sql查询Lots.Where(l => l.Side == 'A')
时,它会生成以下SQL
-- Region Parameters
DECLARE @p0 Int = 65
-- EndRegion
SELECT ..., [t0].[Side], ...
FROM [Lot] AS [t0]
WHERE UNICODE([t0].[Side]) = @p0
然而,使用Lots.Where(l => l.Side.Equals('A'))
,它会产生
-- Region Parameters
DECLARE @p0 Char(1) = 'A'
-- EndRegion
SELECT ..., [t0].[Side], ...
FROM [Lot] AS [t0]
WHERE [t0].[Side] = @p0
它会出现(尽管是天真的)检查,后者会稍快一些,因为它不需要调用UNICODE
。
使用int
,smallint
或varchar
列,生成的SQL与==
或.Equals
之间没有区别,为什么char(1)
和相应的C#类型char
不同?
有没有办法预测给定的列类型是否会产生两种形式的相等检查?
编辑:
我检查了MS SQL支持的每种类型,只有char(1)
和nchar(1)
显示此行为。两者都以System.Char
类型在LinqToSql中表示。如果这是一个深思熟虑的决定,那么我会期望在binary(1)
上有相同的行为,可以用System.Byte
表示(但System.Linq.Binary
的长度为1
编辑2:如果它是相关的,我使用LINQPad来查看创建的SQL。我假设Linqpad会使用系统的LinqToSQL,但我今天意识到这个假设可能存在缺陷。
编辑3:我运行了一个快速的VS项目来测试系统LinqToSQL,我们得到了相同的结果:
代码:
static void Main(string[] args)
{
var db = new DataClasses1DataContext {Log = Console.Out};
Console.Out.WriteLine("l.Side == 'A'");
Console.Out.WriteLine("=============");
Console.Out.WriteLine();
foreach (Lot ll in db.Lots.Where(l => l.Side == 'A'))
{
break;
}
Console.Out.WriteLine();
Console.Out.WriteLine("---------------------------------------");
Console.Out.WriteLine();
Console.Out.WriteLine("l.Side.Equals('A')");
Console.Out.WriteLine("==================");
Console.Out.WriteLine();
foreach (Lot ll in db.Lots.Where(l => l.Side.Equals('A')))
{
break;
}
Console.In.Read();
}
输出:
l.Side == 'A'
=============
SELECT ..., [t0].[Side], ...
FROM [dbo].[Lot] AS [t0]
WHERE UNICODE([t0].[Side]) = @p0
-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [65]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.6.1532.0
---------------------------------------
l.Side.Equals('A')
==================
SELECT ..., [t0].[Side], ...
FROM [dbo].[Lot] AS [t0]
WHERE [t0].[Side] = @p0
-- @p0: Input Char (Size = 1; Prec = 0; Scale = 0) [A]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.6.1532.0
值得注意的是,在== 'A'
版本中,参数作为int
传递,而在.Equals
版本中,参数传递为char
。
答案 0 :(得分:12)
对此有一些documentation:
SQL Server中的不匹配: 固定长度的字符类型。 Transact-SQL区分Unicode和非Unicode类别,并且在每个类别中有三种不同的类型:固定长度nchar / char,可变长度nvarchar / varchar和更大的ntext / text。固定长度字符类型可以映射到CLR System.Char类型以检索字符,但它们实际上并不对应于转换和行为中的相同类型。
L2S源代码只有一个地方使用字符串文字"UNICODE"
:
看起来函数显示的必要前提条件是类型为SqlUnary
的{{1}}语法树节点:
我不知道你是如何设法满足Convert
条件的。我认为你的类型不匹配。该列是否真的映射为IsNumeric
?
System.Char
调用可能不会触发此代码路径。这可能是一个L2S错误。
Equals
在源代码中的多个位置进行了翻译。这是其中之一:
看起来这会绕过任何参数转换。它并不关心论证是什么。这可能会因各种查询而失败(因此可能存在错误)。我想知道如果你写Equals
会发生什么。我想这会直接翻译成SQL。
我现在已经复制了它。将列映射到l.Side.Equals(1.2m)
。这可以修复生成的SQL。执行计划显示可以使用正在生成的SQL进行索引搜索。