Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 2008 带ExecuteReader的SQL Server链式存储过程中的错误处理_Sql Server 2008_Stored Procedures_Ado.net_Error Handling - Fatal编程技术网

Sql server 2008 带ExecuteReader的SQL Server链式存储过程中的错误处理

Sql server 2008 带ExecuteReader的SQL Server链式存储过程中的错误处理,sql-server-2008,stored-procedures,ado.net,error-handling,Sql Server 2008,Stored Procedures,Ado.net,Error Handling,我将一些存储过程链接在一起,并在使错误处理正常工作时遇到了一些问题。由于其中一些存储过程是长期运行的,我在存储过程中使用了SqlInfoMessageEventHandler和RAISERROR('whatever',10,1)和NOWAIT等代码来向用户报告操作的进度。为了做到这一点,我读到您不能使用cmd.ExecuteNonQuery(),而必须使用cmd.ExecuteReader()。我已经试过了,似乎确实如此;我没有看到来自ExecuteOnQuery的任何消息 但我发现的问题是,当

我将一些存储过程链接在一起,并在使错误处理正常工作时遇到了一些问题。由于其中一些存储过程是长期运行的,我在存储过程中使用了
SqlInfoMessageEventHandler
RAISERROR('whatever',10,1)和NOWAIT
等代码来向用户报告操作的进度。为了做到这一点,我读到您不能使用cmd.ExecuteNonQuery(),而必须使用cmd.ExecuteReader()。我已经试过了,似乎确实如此;我没有看到来自ExecuteOnQuery的任何消息

但我发现的问题是,当我使用ExecuteReader时,如果我存储的进程抛出任何错误,那么它们就会被忽略。这里我指的是我的.NET应用程序,它从一个try块调用这个存储的proc,当存储的proc遇到错误时(如SELECT 1/0),执行永远不会进入catch块,而是提交我的事务。这方面的一个例子如下:

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TempTstTbl]') AND type in (N'U'))
DROP TABLE [dbo].[TempTstTbl]

CREATE TABLE [dbo].[TempTstTbl] (
    Step INT,
    Val  VARCHAR(50)
)

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Child]') AND type in (N'P', N'PC'))

DROP PROCEDURE [dbo].[Child]
GO 
CREATE PROCEDURE [dbo].[Child]
AS
BEGIN
BEGIN TRY
    INSERT INTO [dbo].[TempTstTbl] (Step, Val) VALUES (1, 'FROM CHILD BEFORE FAULT')
    SELECT 1/0
    --RAISERROR ('This should really fail', 16, 2)
    INSERT INTO [dbo].[TempTstTbl] (Step, Val) VALUES (2, 'FROM CHILD AFTER FAULT')
END TRY
BEGIN CATCH
    DECLARE @ErrorMessage NVARCHAR(4000);
    DECLARE @ErrorSeverity INT;
    DECLARE @ErrorState INT;

    SELECT 
        @ErrorMessage = ERROR_MESSAGE(),
        @ErrorSeverity = ERROR_SEVERITY(),
        @ErrorState = ERROR_STATE();

    -- Use RAISERROR inside the CATCH block to return error
    -- information about the original error that caused
    -- execution to jump to the CATCH block.
    RAISERROR (@ErrorMessage, -- Message text.
               @ErrorSeverity, -- Severity.
               @ErrorState -- State.
               );
END CATCH;
END
GO

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Parent]') AND type in (N'P', N'PC'))

DROP PROCEDURE [dbo].[Parent]
GO
CREATE PROCEDURE [dbo].[Parent]
AS
BEGIN
BEGIN TRY
    INSERT INTO [dbo].[TempTstTbl] (Step, Val) VALUES (1, 'FROM PARENT BEFORE CHILD')
    Exec [dbo].[Child]
    INSERT INTO [dbo].[TempTstTbl] (Step, Val) VALUES (2, 'FROM PARENT AFTER CHILD')
END TRY
BEGIN CATCH
    DECLARE @ErrorMessage NVARCHAR(4000);
    DECLARE @ErrorSeverity INT;
    DECLARE @ErrorState INT;

    SELECT 
        @ErrorMessage = ERROR_MESSAGE(),
        @ErrorSeverity = ERROR_SEVERITY(),
        @ErrorState = ERROR_STATE();

    -- Use RAISERROR inside the CATCH block to return error
    -- information about the original error that caused
    -- execution to jump to the CATCH block.
    RAISERROR (@ErrorMessage, -- Message text.
               @ErrorSeverity, -- Severity.
               @ErrorState -- State.
               );
END CATCH;
END
GO

EXEC [dbo].[Parent]
SELECT * FROM [dbo].[TempTstTbl]
使用一些.NET代码,例如

private void button4_Click(object sender, EventArgs e)
{
    using (SqlConnection conn = new SqlConnection(@"Data Source=XPDEVVM\XPDEV;Initial Catalog=MyTest;Integrated Security=SSPI;"))
    {
        conn.Open();
        using (SqlTransaction trans = conn.BeginTransaction())
        {
            using (SqlCommand cmd = conn.CreateCommand())
            {
                cmd.Transaction = trans;
                cmd.CommandText = "[cfg].[Parent]";
                cmd.CommandType = CommandType.StoredProcedure;

                try
                {
                    -- cmd.ExecuteReader(); -- Using this instead of ExecuteNonQuery means the divide by 0 error in the stored proc is ignored, and everything is committed :(
                    cmd.ExecuteNonQuery();
                    trans.Commit();
                }
                catch (Exception ex)
                {
                    trans.Rollback();
                }
            }
        }
    }
}

有人知道如何从存储过程中获取进度消息,但如果存储过程中出现错误,仍会捕获.NET异常吗?

似乎这个问题源于DataReader的工作方式。我第一次在纳尔逊·罗瑟梅尔(Nelson Rothermel)对另一个SO问题的评论中发现了一个暗示

然后,我进一步阅读了有关本问题的详细信息,理查德·麦金农(Richard McKinnon)给出了以下示例作为解决该问题的方法(我的重点)

在严重性>10的情况下尝试相同的操作(我使用的是11),并将选择行添加到SP(我使用NorthWind DB进行了检查)。你会看到的 当您有一个SELECT来检索数据时,您永远不会得到 例外

[原始信息剪辑]

在这种情况下,ExecuteReader()将启动第一组进程 结果,选择语句。要获得下一组结果,请 RAISERROR,您需要调用NextResult()

因此,只要看看错误,我就会将代码从以前更改为 像这样,

SqlDataReader dr=command.ExecuteReader()NextResult博士() Close博士()

我尝试将dr.NextResult()添加到我的代码中,它似乎已经解决了这个问题


这样,我就可以从存储的进程中获取信息消息,但也可以捕获存储进程中出现的错误。

这个问题似乎源于DataReader的工作方式。我第一次在纳尔逊·罗瑟梅尔(Nelson Rothermel)对另一个SO问题的评论中发现了一个暗示

然后,我进一步阅读了有关本问题的详细信息,理查德·麦金农(Richard McKinnon)给出了以下示例作为解决该问题的方法(我的重点)

在严重性>10的情况下尝试相同的操作(我使用的是11),并将选择行添加到SP(我使用NorthWind DB进行了检查)。你会看到的 当您有一个SELECT来检索数据时,您永远不会得到 例外

[原始信息剪辑]

在这种情况下,ExecuteReader()将启动第一组进程 结果,选择语句。要获得下一组结果,请 RAISERROR,您需要调用NextResult()

因此,只要看看错误,我就会将代码从以前更改为 像这样,

SqlDataReader dr=command.ExecuteReader()NextResult博士() Close博士()

我尝试将dr.NextResult()添加到我的代码中,它似乎已经解决了这个问题

这样,我就可以从存储的进程中获取信息消息,但也可以捕获在存储的进程中引发的错误