这两个语句在逻辑上与我看起来相同,但它们导致生成不同的SQL:
#1
var people = _DB.People.Where(p => p.Status == MyPersonEnum.STUDENT.ToString());
var ids = people.Select(p => p.Id);
var cars = _DB.Cars.Where(c => ids.Contains(c.PersonId));
#2
string s = MyPersonEnum.STUDENT.ToString();
var people = _DB.People.Where(p => p.Status == s);
var ids = people.Select(p => p.Id);
var cars = _DB.Cars.Where(c => ids.Contains(c.PersonId));
示例#1不起作用,但示例#2起作用。
var people
查询生成的SQL对于两者都是相同的,但 final 查询中的SQL不同,如下所示:
#1
SELECT [t0].[PersonId], [t0].[etc].....
FROM [Cars] AS [t0]
WHERE EXISTS(
SELECT NULL AS [EMPTY]
FROM [People] AS [t1]
WHERE ([t1].[Id] = [t0].[PersonId]) AND ([t1].[Status] = (CONVERT(NVarChar,@p0)))
)
#2
SELECT [t0].[PersonId], [t0].[etc].....
FROM [Cars] AS [t0]
WHERE EXISTS(
SELECT NULL AS [EMPTY]
FROM [People] AS [t1]
WHERE ([t1].[Id] = [t0].[PersonId]) AND ([t1].[Status] = @p0)
)
为什么会出现这种差异?
到目前为止,我所做的一切都是为了检查调试器中的查询。但是,在设置了Jon建议的记录器之后,似乎执行的 real sql是不同的。
#1
SELECT [t1].[Id], [t1].etc ... [t0].Id, [t1].etc ...
FROM [Cars] AS [t0], [People] AS [t1]
WHERE ([t1].[Id] = [t0].[PersonId]) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM [People] AS [t2]
WHERE ([t2].[Id] = [t0].[PersonId]) AND ([t2].[Status] = (CONVERT(NVarChar,@p0)))
)) AND ([t1].[Status] = @p1)
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [2]
-- @p1: Input NVarChar (Size = 7; Prec = 0; Scale = 0) [STUDENT]
#2
SELECT [t1].[Id], [t1].etc ... [t0].Id, [t1].etc ...
FROM [Cars] AS [t0], [People] AS [t1]
WHERE ([t1].[Id] = [t0].[PersonId]) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM [People] AS [t2]
WHERE ([t2].[Id] = [t0].[PersonId]) AND ([t2].[Status] = @p0)
)) AND ([t1].[Status] = @p1)
-- @p0: Input NVarChar (Size = 7; Prec = 0; Scale = 0) [STUDENT]
-- @p1: Input NVarChar (Size = 7; Prec = 0; Scale = 0) [STUDENT]
答案 0 :(得分:1)
MyPersonEnum.STUDENT.ToString()
位于表达式树中 - 它是LINQ to SQL必须转换为SQL的一部分。我有兴趣看看执行查询时@p0
是什么......
在第二个版本中,您已经评估了表达式,因此LINQ to SQL只会看到对已经是字符串的变量的引用。
我们知道它们的意思相同,但可能是LINQ to SQL没有足够的知识来理解它。
出于兴趣,他们两个都有效吗?
编辑:好的,所以第二个版本有效。我建议你使用那种形式:)在一个理想的世界中,两者都可以工作 - 但在这种情况下,你似乎需要帮助LINQ to SQL。答案 1 :(得分:1)
首先,想想e Enum的双重性:
enum MyPersonEnum
{
STUDENT, // implicit 1
TEACHER, // implicit 2
DIRECTOR = 10 // explicit 10
}
...
Assert.AreEqual(1, (int)MyPersonEnum.STUDENT);
Assert.AreEqual("STUDENT", MyPersonEnum.STUDENT.ToString());
在第二个示例中,C#已将Enum转换为字符串,因此不需要转换,并且假设您的数据库People.Status列接受“STUDENT”,“TEACHER”,“DIRECTOR”字符串作为逻辑中的有效值。
区别在于,CLR中的枚举内部表示是整数,第一个示例,@ p参数作为整数传递,它是L2S查询构建器行为,这就是转换的原因。
如果您的数据库列是一个int,在我的示例中将值分配给Enum成员{1,2,10},那么第一个将起作用。