5

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

为查询生成的 SQLvar people是相同的,但最终查询中的 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)
    )

为什么会有这种差异?

编辑:

到目前为止,我为生成 SQL 所做的只是检查调试器中的可查询对象。但是,在按照 Jon 的建议设置了一个 logger 之后,执行的真实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]
4

2 回答 2

1

不,它们是不同的。在第一个版本中,表达式MyPersonEnum.STUDENT.ToString()位于表达式树中——它是 LINQ to SQL 必须转换为 SQL 的一部分。我很想看看@p0执行查询的时间是什么......

在第二个版本中,您已经评估了表达式,因此 LINQ to SQL 只会看到对已经是字符串的变量的引用。

我们知道它们的含义相同,但大概 LINQ to SQL 没有足够的知识来理解这一点。

出于兴趣,它们都有效吗?

编辑:好的,所以第二个版本有效。我建议你使用这种形式:) 在理想的世界中,两者都可以工作 - 但在这种情况下,你似乎需要帮助 LINQ to SQL 一点。

于 2009-12-23T11:13:38.017 回答
1

首先,考虑枚举的双重性质:

enum MyPersonEnum
{
  STUDENT, // implicit 1
  TEACHER, // implicit 2
  DIRECTOR = 10 // explicit 10
}

...

Assert.AreEqual(1, (int)MyPersonEnum.STUDENT);
Assert.AreEqual("STUDENT", MyPersonEnum.STUDENT.ToString());

In the second example, C# have converted Enum to string, so no conversion needed, and it's assumed that your database People.Status column accepts "STUDENT", "TEACHER", "DIRECTOR" strings as valid values in the logic.

The difference is, enum internal representation in CLR is integer, and the first example, @p parameter is passed as an integer, it's an L2S query builder behaviour, that's why the conversion.

The first one would work, if your database column was an int that takes values assigned to the Enum members {1,2,10} in my example.

于 2009-12-23T18:14:27.650 回答