这两个LINQtoSQL语句之间有什么区别?

时间:2009-12-23 11:07:25

标签: c# linq-to-sql iqueryable generated-sql

这两个语句在逻辑上与我看起来相同,但它们导致生成不同的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]

2 个答案:

答案 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},那么第一个将起作用。