【发布时间】:2015-06-18 11:53:27
【问题描述】:
我在 SqlCommand 对象的“ExecuteScalar()”方法中遇到了一个有趣的问题。
我有一个存储过程,它在表中创建一条新记录。它包含一个“插入”语句,其中有一个“输出”子句(因为创建的记录利用了一个标识列和一些默认值)。
这很好用,“ExecuteScalar”返回标识列值(第 1 行,第 1 列)。
但是,在测试中,我故意调用了我的存储过程两次,第二次预计会在数据表中遇到唯一约束并失败 (在SP).
到目前为止一切顺利,除了第二次调用返回一个空行集(我可以验证我是否从 SQLMgr 运行它)并且 ExecuteScalar 返回一个空值 - 但没有不要抛出异常。
这不是预期的,给我留下了一个有趣的问题。如何使用 ExecuteScalar - 为了在成功的情况下返回 id 列值 - 但如果发生错误,它会失败吗?
我知道,如果我从“插入”中删除“输出”子句,则会按预期抛出异常。
如果这是预期的行为,我应该如何调用我的 SP,以便返回 id 值,并在我的约束被击中时引发异常?
很明显,我可以在存储过程中做各种诡计多端的操作(比如使用 scope_identity 插入然后选择),并且 - 正如我在测试中所做的那样 - 我可以检查 null返回并进行后续的 ExecuteNonQuery 调用(确实会引发异常)。但是,考虑到“输出”子句的用处,这一切似乎都是捏造的。
我做了一些“谷歌搜索”,并找到了对 ExecuteScalar“吃”异常的引用,但这只是一个传递引用。
想法?
-- 编辑 1--
我的意思是,在进一步调查编写下面的“简单案例”后,(显然)如果我有一个存储过程,它有一个“try catch”和一个违反唯一约束的插入,当通过 ExecuteScalar 调用,我没有收到异常。
如果我删除“try/catch/throw” - 我会得到异常。
如果我删除“输出” - 我会得到异常
-- 编辑 2--
这里有一些示例(这是非常减少的......是的,我使用“try/catch”来跳过其他功能:
表格如下:
CREATE TABLE [dbo].[test]
(
[id] [int] IDENTITY(1,1) NOT NULL,
[value] [varchar](10) NOT NULL,
[description] [varchar](100) NOT NULL,
CONSTRAINT [PK_test_1] PRIMARY KEY CLUSTERED ([id] ASC) ON [PRIMARY]
) ON [PRIMARY]
END
GO
CREATE UNIQUE NONCLUSTERED INDEX [UNQ_test_description] ON [dbo].[test]([description] ASC) ON [PRIMARY]
GO
SP 看起来像这样:
create procedure dbo.fred
(
@Code varchar(10),
@Description varchar(100)
)
as
begin
begin try
insert into dbo.test
(value, [description])
output
inserted.ID
values
(@Code, @Description)
end try
begin catch
throw
end catch
end
【问题讨论】:
-
尝试添加一个最小示例来编译您所看到的问题。你越容易为每个人检查这个,你就会越快得到帮助:)
-
您是说在一个 ExecuteScalar 方法中执行相同的过程两次?请注意,ExecuteScalar 会忽略除第一个结果集的第一列之外的所有内容。这意味着这将吃掉返回标量值的语句之后的后续异常。
标签: sql-server stored-procedures exception-handling