使用SqlDataAdapter.Fill(DataTable)未在.NET中捕获存储过程的异常

时间:2014-12-09 17:10:12

标签: vb.net exception-handling sql-server-2012 sqldatareader sqldataadapter

我有一个存储过程,我正在从VB.NET执行。 SP应将记录插入表中并将一组返回给调用应用程序。返回的集合是插入的记录。

如果INSERT失败,则会在SP中捕获并重新抛出异常,但我从未在应用程序中看到异常。严重性级别为14,所以我应该看到它。

这是存储过程:

BEGIN TRY    

    BEGIN TRANSACTION 

        -- Declare local variables
        DECLARE @DefaultCategoryID AS BIGINT = 1                -- 1 = 'Default Category' (which means no category)
        DECLARE @DefaultWeight AS DECIMAL(18,6) = 0
        DECLARE @InsertionDate AS DATETIME2(7) = GETDATE()
        DECLARE @SendToWebsite AS BIT = 0                       -- 0 = 'NO'
        DECLARE @MagentoPartTypeID AS BIGINT = 1                -- For now, this is the only part type we are importing from COPICS ('simple' part type)

        DECLARE @NotUploaded_PartStatusID AS TINYINT = 0        -- 0 = 'Not Uploaded'
        DECLARE @Enabled_PartStatusID AS TINYINT = 1            -- 1 = 'Enabled'
        DECLARE @Disabled_PartStatusID AS TINYINT = 2           -- 2 = 'Disabled'


        -- Get the part numbers that will be inserted (this set will be returned to calling procedure).
        SELECT c.PartNumber
        FROM
            COPICSPartFile c 
            LEFT JOIN Part p on c.PartNumber = p.PartNumber
        WHERE 
            p.PartNumber IS NULL        

        -- Insert new records from COPICSPartFile (records that don't exist - by PartNumber - in Part table)
        INSERT INTO Part
            ([PartNumber]
            ,[ReplacementPartNumber]
            ,[ShortDescription]
            ,[ListPrice]
            ,[PartStatusTypeID]
            ,[Weight]
            ,[CategoryID]
            ,[DateInserted]
            ,[SendToWebsite]
            ,[FileName]
            ,[MagentoPartTypeID]
            ,[PrintNumber])
        SELECT
            c.PartNumber
            ,c.ReplacementPartNumber
            ,c.ShortDescription
            ,c.ListPrice
            ,CASE WHEN c.PartStatusTypeID = @Enabled_PartStatusID THEN @NotUploaded_PartStatusID ELSE @Disabled_PartStatusID END
            ,@DefaultWeight
            ,@DefaultCategoryID
            ,@InsertionDate
            ,@SendToWebsite
            ,@FileName
            ,@MagentoPartTypeID
            ,c.PrintNumber
        FROM
            COPICSPartFile c 
            LEFT JOIN Part p on c.PartNumber = p.PartNumber
        WHERE 
            p.PartNumber IS NULL


    COMMIT TRANSACTION;

END TRY

BEGIN CATCH

    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;

    THROW;

END CATCH

这是.net代码:

Try

    'Create command
    Dim command As New SqlCommand
    command.CommandType = CommandType.StoredProcedure
    conn = New SqlConnection(m_ConnectionString)
    command.Connection = conn
    command.CommandText = "trxInsertPartFromCOPICSPartFile"
    With command.Parameters
        .AddWithValue("@FileName", fileName)
    End With
    Dim da As New SqlDataAdapter(command)
    Dim dt As New DataTable
    da.Fill(dt)

    If dt.Rows.Count > 0 Then
        Return dt
    Else
        Return Nothing
    End If

Catch ex As SqlException

    Dim myMessage As String = ex.Message

Finally
    If conn.State <> ConnectionState.Closed Then
        conn.Close()
    End If
End Try

当我试图弄清楚为什么异常(重复键)没有被我的应用程序捕获时,我尝试在SELECT之前在SP中发表INSERT语句瞧。应用程序中捕获了INSERT的异常。

有人可以向我解释为什么SELECT声明会导致这种情况吗?我知道我可以将SELECT分解为另一个SP,但如果可能的话,我想保留所有原子事务。这是预期的行为吗?有办法吗?

感谢。

1 个答案:

答案 0 :(得分:1)

Fill方法吞噬了异常。不要使用该方法,而是创建SqlDataReader,执行command.ExecuteReader(),然后使用阅读器通过DataTable填充Load()。这样,错误应该在ExecuteReader()方法中发生,并且应该是可捕获的。然后你不应该需要SqlDataAdapter

Try
    'Create command
    Dim command As New SqlCommand
    command.CommandType = CommandType.StoredProcedure
    conn = New SqlConnection(m_ConnectionString)
    command.Connection = conn
    command.CommandText = "trxInsertPartFromCOPICSPartFile"
    With command.Parameters
        .AddWithValue("@FileName", fileName)
    End With

    Dim dt As New DataTable
    conn.Open()
    Dim reader As SqlDataReader = command.ExecuteReader()
    dt.Load(reader)

    If dt.Rows.Count > 0 Then
        Return dt
    Else
        Return Nothing
    End If

Catch ex As SqlException

    Dim myMessage As String = ex.Message

Finally
    If conn.State <> ConnectionState.Closed Then
        conn.Close()
    End If
End Try

此外,如果将SELECT和INSERT组合到一个语句中,您可能会在几个级别上更好。您可以通过OUTPUT子句执行此操作,如下所示:

    INSERT INTO Part
        ([PartNumber]
        ,[ReplacementPartNumber]
        ,[ShortDescription]
        ,[ListPrice]
        ,[PartStatusTypeID]
        ,[Weight]
        ,[CategoryID]
        ,[DateInserted]
        ,[SendToWebsite]
        ,[FileName]
        ,[MagentoPartTypeID]
        ,[PrintNumber])
    OUTPUT INSERTED.[PartNumber] -- return the inserted values to the app code
    SELECT
        c.PartNumber
        ,c.ReplacementPartNumber
        ,c.ShortDescription
        ,c.ListPrice
        ,CASE WHEN c.PartStatusTypeID = @Enabled_PartStatusID
                THEN @NotUploaded_PartStatusID
                ELSE @Disabled_PartStatusID END
        ,@DefaultWeight
        ,@DefaultCategoryID
        ,@InsertionDate
        ,@SendToWebsite
        ,@FileName
        ,@MagentoPartTypeID
        ,c.PrintNumber
    FROM
        COPICSPartFile c 
        LEFT JOIN Part p on c.PartNumber = p.PartNumber
    WHERE 
        p.PartNumber IS NULL