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

8
当使用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'

我理解,插入/选择是为了在保存后立即检索CustomerId列的值。据我所知,scope_identity()返回该值,那么为什么没有像下面这样的东西

SELECT scope_identity()

有没有什么东西可以避免需要物理读取所有的内容?

谢谢, Manuel


不是针对你的问题,但是你应该为像“name”和“FirstName”这样的列使用更合适的数据类型,而不是使用“nvarchar(max)”。 - Martin Smith
1
也许是为了获得具有正确数据类型的列的结果。 - Martin Smith
1个回答

1

正确。 scope_identity() 用于获取生成的 CustomerId 值,以便EF将其用作实体键。我认为,但我必须猜测,因为它没有记录在案,SELECT 是在 Customer 表上执行的,以确保检索到的 scope_identity() 确实与 CustomerId 相关。可能存在一种情况,即 INSERT 触发更多的插入,因此 scope_identity() 被分配给另一条记录。

查询 Customer 表的第二个原因是,该查询是在一个方法中生成的,该方法还可以向 SELECT 子句添加计算列。无论如何,查询实体表可能更方便。

添加 WHERE @@ROWCOUNT > 0 子句是为了确保 INSERT 语句影响了预期数量的行。在 EF 的源代码中,有一个注释:

请注意,我们根据行数过滤,以确保如果未修改任何行,则不返回任何行。


3
关于你提出的“插入触发更多插入”的理论,scope_identity 永远不会从另一个作用域(比如触发器)中的插入获取标识值。这就是为什么它比 @@identity 更可靠的原因。 - Martin Smith
@MartinSmith 不是在另一个作用域中。但也许有情况是在同一作用域中进行插入操作。我认为他们只是谨慎。但像你上面所说的获取正确的数据类型听起来也是一个很好的理由。 - Gert Arnold
@gert-arnold:你的第二个猜测不可能是原因,因为插入后只选择了id列,所以它不会获取计算列的值。如果第一个原因正确,那么一个代替触发器在客户表上进行3次插入而不是一次插入可能会导致错误的scope_identity()。那么检索到的值不可能是错误的吗? - Manuel R. Wenk
3
触发器在不同的作用域中运行。当存在计算列(在 EF 类模型中标记为 Computed)时,它们也会在同一条 SQL 语句中被选择。尽管如此,我不介意 EF 团队中的某个人在这里插话。 - Gert Arnold

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接