【问题标题】:What's the difference between these two LINQtoSQL statements?这两个 LINQtoSQL 语句有什么区别?
【发布时间】:2023-03-15 11:30:01
【问题描述】:

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

为什么会有这种差异?

编辑:

到目前为止,为了生成 SQL,我所做的只是检查调试器中的可查询对象。但是,按照 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]

【问题讨论】:

  • 如果您尝试 string s = MyPersonnum.STUDENT.ToString(); 是否有效?
  • 如示例 #2?是的,这实际上是我在那里使用的代码,只是按习惯输入 var,我会编辑我的帖子

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


【解决方案1】:

首先,想想 e 枚举的双重性质:

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,在我的示例中采用分配给枚举成员 {1,2,10} 的值,则第一个可以工作。

【讨论】:

    【解决方案2】:

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

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

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

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

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

    【讨论】:

    • 你的意思是在#1 MyPersonEnum.STUDENT.ToString() 在编译时根本不计算?
    • 已编辑以提供更多信息,如果您在调试器中单步执行并在第一步中“枚举 IEnumerable”(即人员查询),它将获取您期望的所有结果。试图取车时它会掉下来
    • @DTashkinov:在第一个版本中,它构建了一个表达式树,是的。
    • 我可以使用有效的版本,更多的是想知道是什么问题在驱使我 ;) 我如何检查@p0 执行查询时的值?
    • 那么也许问题是在第一个版本中编译器可以确定字符串的长度或其他内容,以确保它可以按原样传递给 SQL,而在第二个版本中它无法确定它,所以只是万一广告转换功能。
    猜你喜欢
    • 2016-04-16
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 2015-05-31
    • 2020-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多