使用 INSERT...OUTPUT.inserted 时,SqlDataReader.RecordsAffected 错误地返回 -1
我们依赖 SqlDataReader.RecordsAffected
来计算存储过程修改的行数。
MSDN 对其定义如下:
更改、插入或删除的行数;如果没有行受到影响或者语句失败,则为 0; SELECT 语句为 -1...该属性的值是累积的。例如,如果批量插入两条记录,则RecordsAffected的值为2。
看来 ADO.NET 会误解任何使用 OUTPUT
的语句子句作为SELECT
语句,并为RecordsAffected
返回-1,而不是实际修改的行数。
例如:
CREATE TABLE dbo.example (
a INT
, b VARCHAR(10)
, c DATETIME2(3) DEFAULT(SYSUTCDATETIME())
);
INSERT INTO dbo.example (
a
, b
)
OUTPUT inserted.c -- Comment out this line and RecordsAffected goes from -1 to 1.
VALUES (
1
, 'blah'
);
ADO.NET 的这种行为是有意为之还是错误造成的?
作为记录,我们计划更改代码以使用 @@ROWCOUNT
显式捕获已修改行的计数,并将它们作为存储过程中的 OUTPUT
参数返回。
We rely on SqlDataReader.RecordsAffected
to count the number of rows modified by a stored procedure.
MSDN states its definition as:
The number of rows changed, inserted, or deleted; 0 if no rows were affected or the statement failed; and -1 for SELECT statements... The value of this property is cumulative. For example, if two records are inserted in batch mode, the value of RecordsAffected will be two.
It appears that ADO.NET misinterprets any statement using the OUTPUT
clause as a SELECT
statement and returns -1 for RecordsAffected
instead of the actual count of modified rows.
For example:
CREATE TABLE dbo.example (
a INT
, b VARCHAR(10)
, c DATETIME2(3) DEFAULT(SYSUTCDATETIME())
);
INSERT INTO dbo.example (
a
, b
)
OUTPUT inserted.c -- Comment out this line and RecordsAffected goes from -1 to 1.
VALUES (
1
, 'blah'
);
Is this ADO.NET behavior by design or by error?
For the record, we plan to change our code to explicitly capture counts of modified rows using @@ROWCOUNT
and return them as OUTPUT
parameters in our stored procedures.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
嗯,密切关注文档肯定会有所帮助。
再次,来自 MSDN:
这有点谎言。
RecordsAffected
在关闭SqlDataReader
之前设置,但并非始终如此。我们在关闭对象之前查询它,并且一直工作得很好——直到我们开始在 T-SQL 中使用OUTPUT insert
。关闭
SqlDataReader
后查询RecordsAffected
会产生正确的修改行计数,无论是否带有OUTPUT
子句。Well, it certainly helps to pay close attention to the documentation.
Again, from MSDN:
This is somewhat of a lie.
RecordsAffected
is set before you closeSqlDataReader
, but not all the time. We were querying it before closing the object and that always worked fine--until we starting usingOUTPUT inserted
in our T-SQL.Querying
RecordsAffected
after closing yourSqlDataReader
yields the correct modified row count, with or without theOUTPUT
clause.