为什么Entity Framework 6在插入后只选择scope_identity()?

Man*_*enk 7 .net sql-server entity-framework

使用EF 6.1保存实体时,将生成并执行以下SQL代码:

exec sp_executesql N'INSERT [dbo].[Customers]([Name], [FirstName])
VALUES (@0, @1)
SELECT [CustomerId]
FROM [dbo].[Customers]
WHERE @@ROWCOUNT > 0 AND [CustomerId] = scope_identity()',N'@0 nvarchar(max) ,@1 nvarchar(max) ',@0=N'Wenk',@1=N'Manuel'
Run Code Online (Sandbox Code Playgroud)

我明白,插入/选择已完成,以便在保存后检索CustomerId列immediatley的值.据我所知,scope_identity()返回值,为什么没有类似的东西

SELECT scope_identity()
Run Code Online (Sandbox Code Playgroud)

而不是所有需要物理读取的东西?

干杯,曼努埃尔

Ger*_*old 1

正确的。scope_identity()在那里获取生成的CustomerId值,因此 EF 可以将其用作实体键。我想,但我必须猜测,因为它没有记录在案,这SELECT是在Customer桌子上完成的,以确保检索到的内容scope_identity()确实与CustomerId. 在某些情况下,一条记录可能INSERT会触发更多插入,因此scope_identity()会被分配给另一条记录。

查询表的第二个原因Customer是该查询是通过一种方法生成的,该方法也可能将计算列添加到 SELECT 子句。无论如何,查询实体表可能更方便。

添加该WHERE @@ROWCOUNT > 0子句是为了确保预期的行数受到该INSERT语句的影响。EF的源码中有这样一条注释:

请注意,我们根据行计数进行过滤,以确保在没有修改任何行的情况下不会返回任何行。

  • 关于您的“插入触发更多插入”理论,“scope_identity”永远不会从另一个范围(例如触发器)的插入中获取身份值。这就是为什么更喜欢它而不是“@@identity” (3认同)
  • 触发器在不同的范围内运行。当然,当存在计算列(在 EF 类模型中标记为“计算”)时,它们也会在同一 SQL 语句中被选择。尽管如此,我不介意 EF 团队的某个人在这里插话。 (3认同)