简体   繁体   中英

Trouble Executing SQL Stored Procedure C#

Im trying to execute the following query from a console application.

CREATE PROCEDURE main.usp_setup
AS
SET TRANSACTION ISOLATION LEVEL
REPEATABLE READ
BEGIN TRANSACTION
    BEGIN

        BEGIN TRY
        EXEC main.usp_importXml[C:\Users\User\Desktop\people.xml];
        END TRY

        BEGIN CATCH
        INSERT INTO main.errorLog(EntryTime,ErrorNumber,ErrorMessage,ErrorProcedure,ErrorLineNumber,ErrorSeverity,ErrorState)
        VALUES (CURRENT_TIMESTAMP,ERROR_NUMBER(),'Failed to import XML',ERROR_PROCEDURE(),ERROR_LINE(),ERROR_SEVERITY(),ERROR_STATE())  
            declare @message nvarchar(45);
            set @message = 'Failed at Import XML - ' + CAST(SCOPE_IDENTITY()AS NVARCHAR(32)) ;
            THROW 50001,@message , 20;
        END CATCH

        BEGIN TRY
        EXEC main.usp_afterimport;
        END TRY

        BEGIN CATCH
        INSERT INTO main.errorLog(EntryTime,ErrorNumber,ErrorMessage,ErrorProcedure,ErrorLineNumber,ErrorSeverity,ErrorState)
        VALUES (CURRENT_TIMESTAMP,ERROR_NUMBER(),'Failed to Populate',ERROR_PROCEDURE(),ERROR_LINE(),ERROR_SEVERITY(),ERROR_STATE())    

            set @message = 'Failed to Populate' + CAST(SCOPE_IDENTITY()AS NVARCHAR(32)) ;
            THROW 50001,@message , 20;
        END CATCH
        COMMIT
    END
GO

Code in Console Application :

SqlConnection conn = new SqlConnection();
            conn.ConnectionString =
            "Data Source=DELLC;" +
            "Initial Catalog=hr;" +
            "User id=geordey;" +
            "Password=1234;";
            conn.Open();



  SqlCommand cmd = new SqlCommand("main.usp_setup", conn);
                        cmd.CommandType = System.Data.CommandType.StoredProcedure;
                        int a = cmd.ExecuteNonQuery();

                        if(a==-1)
                        {
                            Console.WriteLine("Error");
                        }
                        else
                        {
                            Console.WriteLine("Loaded");
                        }

But when executed the following error is given:

System.Data.SqlClient.SqlException: 'The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.

Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.'

BEGIN TRANSACTION
BEGIN TRY
    EXEC main.usp_importXml[C:\Users\User\Desktop\people.xml];
BND TRY
BEGIN CATCH
   INSERT INTO ...
END CATCH
COMMIT

You absolutely cannot do this. Inside a CATCH block you must check for the XACT_STATE() value and act accordingly:

  • 1 The current request has an active user transaction. The request can perform any actions, including writing data and committing the transaction.
  • 0 There is no active user transaction for the current request.
  • -1 The current request has an active user transaction, but an error has occurred that has caused the transaction to be classified as an uncommittable transaction.

Not only that, but you cannot place the COMMIT after the CATCH. If the transaction has rolled back, what are you going to commit? You should place the COMMIT before the CATCH, and you can have only one TRY/CATCH block, not two.

If you want a good pattern to model after, read Exception handling and nested transactions :

begin
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;
    begin try
        if @trancount = 0
            begin transaction
        else
            save transaction usp_my_procedure_name;

        -- Do the actual work here

lbexit:
        if @trancount = 0   
            commit;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback transaction usp_my_procedure_name;

        raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
    end catch   
end
go

I think you are missing an END before the COMMIT call.

See my answer below:

CREATE PROCEDURE main.usp_setup
AS
SET TRANSACTION ISOLATION LEVEL
REPEATABLE READ
BEGIN TRANSACTION
        BEGIN TRY
        EXEC main.usp_importXml[C:\Users\User\Desktop\people.xml];
        END TRY

        BEGIN CATCH
        INSERT INTO main.errorLog(EntryTime,ErrorNumber,ErrorMessage,ErrorProcedure,ErrorLineNumber,ErrorSeverity,ErrorState)
        VALUES (CURRENT_TIMESTAMP,ERROR_NUMBER(),'Failed to import XML',ERROR_PROCEDURE(),ERROR_LINE(),ERROR_SEVERITY(),ERROR_STATE())  
            declare @message nvarchar(45);
            set @message = 'Failed at Import XML - ' + CAST(SCOPE_IDENTITY()AS NVARCHAR(32)) ;
            THROW 50001,@message , 20;
        END CATCH

        BEGIN TRY
        EXEC main.usp_afterimport;
        END TRY

        BEGIN CATCH
        INSERT INTO main.errorLog(EntryTime,ErrorNumber,ErrorMessage,ErrorProcedure,ErrorLineNumber,ErrorSeverity,ErrorState)
        VALUES (CURRENT_TIMESTAMP,ERROR_NUMBER(),'Failed to Populate',ERROR_PROCEDURE(),ERROR_LINE(),ERROR_SEVERITY(),ERROR_STATE())    

            set @message = 'Failed to Populate' + CAST(SCOPE_IDENTITY()AS NVARCHAR(32)) ;
            THROW 50001,@message , 20;
        END CATCH
COMMIT
GO

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM