简体   繁体   English

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

[英]What's the difference between these two LINQtoSQL statements?

These two statements look the same logically to me, but they're resulting in different SQL being generated: 这两个语句在逻辑上与我看起来相同,但它们导致生成不同的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));

Example #1 doesn't work, but example #2 does. 示例#1不起作用,但示例#2起作用。

The generated SQL for the var people query is identical for both, but the SQL in the final query differs like this: var people查询生成的SQL对于两者都是相同的,但最终查询中的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)
    )

Why is there this difference? 为什么会出现这种差异?

Edit: 编辑:

Up until now all I've done to get the SQL generated is to inspect the queryable in the debugger. 到目前为止,我所做的一切只是为了检查调试器中的可查询性。 However, after setting up a logger as Jon suggested, it seems that the real sql executed is different. 但是,在设置了Jon建议的记录器之后,似乎执行的真实 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]

No, they're different. 不,他们是不同的。 In the first version, the expression MyPersonEnum.STUDENT.ToString() is within the expression tree - it's part of what LINQ to SQL has to convert into SQL. 在第一个版本中,表达式MyPersonEnum.STUDENT.ToString()位于表达式树中 - 它是LINQ to SQL必须转换为SQL的一部分。 I'd be interested to see what @p0 is when the query is executed... 我有兴趣看看执行查询时@p0是什么...

In the second version, you've already evaluated the expression, so LINQ to SQL just sees a reference to a variable which is already a string. 在第二个版本中,您已经评估了表达式,因此LINQ to SQL只会看到对已经是字符串的变量的引用。

We know that they mean the same thing, but presumably LINQ to SQL doesn't have quite enough knowledge to understand that. 我们知道它们的意思相同,但可能是LINQ to SQL没有足够的知识来理解它。

Out of interest, do both of them work? 出于兴趣,他们两个都有效吗?

EDIT: Okay, so the second version works. 编辑:好的,所以第二个版本的工作原理。 I suggest you use that form then :) In an ideal world, both would work - but in this case it seems you need to help LINQ to SQL a bit. 我建议你使用那种形式然后:)在一个理想的世界中,两者都可以工作 - 但在这种情况下,你似乎需要帮助LINQ to SQL一点。

First, think of dual nature of e Enum: 首先,想想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());

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. 在第二个示例中,C#已将Enum转换为字符串,因此不需要转换,并且假设您的数据库People.Status列接受“STUDENT”,“TEACHER”,“DIRECTOR”字符串作为逻辑中的有效值。

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. 区别在于,CLR中的枚举内部表示是整数,第一个示例,@ p参数作为整数传递,它是L2S查询构建器行为,这就是转换的原因。

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. 如果您的数据库列是一个int,在我的示例中将值分配给Enum成员{1,2,10},则第一个将起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM