【问题标题】:Error Calling Stored Procedure from C#/ASP.NET从 C#/ASP.NET 调用存储过程时出错
【发布时间】:2013-09-26 14:49:26
【问题描述】:

以下存储过程 pr_generate_sales_order 为数据库 DB1 生成 2 个表 SO Header 和 SO Detail 中的记录。然后它将 SO Header & Detail 记录从 DB1 导出到 DB2。

每当我尝试从 ASP.Net/C# 调用此 SP 时,它都会生成以下错误消息: 名为“c_customers”的游​​标不存在,不会在数据库中创建记录。

但是,如果我在 SSMS 中直接执行此存储过程 pr_generate_sales_order,那么它可以正常工作并在 DB1 和 DB2 中生成记录。

问题出在哪里?是不是和Begin Try Catch...有关???

USE [DB1]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- ------------------------------------------------------------------------------------
-- Name: pr_generate_sales_order
-- ------------------------------------------------------------------------------------
-- Parameters: 
--    - N/A
--
-- Description: 
--    Generate Sales Order in DB1 & DB2
-- ------------------------------------------------------------------------------------
alter procedure [dbo].[pr_generate_sales_order] () as

Begin

-- --------------------------------------------------------------------------------
-- Variable declaration
-- --------------------------------------------------------------------------------
Declare @v_error_number             nvarchar(10)
Declare @v_error_message_en         nvarchar(1000)

Declare @v_customer_id              int
Declare @v_time_log_id              int
Declare @v_hourly_rate              numeric(18, 5)
Declare @v_total_time               numeric(18, 5)
Declare @v_description              nvarchar(max)

Declare @tmp_time_log Table
(
    time_log_id                     int,
    customer_id                     int,
    sku_id                          int,
    hourly_rate                     numeric(18, 5),
    hours                           int,
    minutes                         int
)


-- --------------------------------------------------------------------------------
-- Main program
-- --------------------------------------------------------------------------------
Set @v_error_number = '0'
Set @v_error_message_en = ''


Begin Try

    Begin Transaction T1


    -- ------------------------------------------------------------------------
    -- 
    -- ------------------------------------------------------------------------
    Insert Into @tmp_time_log
    Select      tl.time_log_id                          as time_log_id
                , tl.customer_id                        as customer_id
                , tl.sku_id                             as sku_id       -- 24/09/2013
                , tl.hourly_rate                        as hourly_rate
                , tl.hours_rounded                      as hours_rounded
                , tl.minutes_rounded                    as minutes_rounded

    From        time_log tl

    Where       tl.transaction_date between '2013-01-06' and getdate() 



    -- ------------------------------------------------------------------------
    -- Open Cursor
    -- ------------------------------------------------------------------------

    -- ------------------------------------------------------------------------
    -- Declare Customer Cursor: Get the list of Customer
    -- ------------------------------------------------------------------------
    Declare c_customers cursor for 
    Select      distinct IsNull(customer_id, 0)
    From        @tmp_time_log

    Open c_customers

    Fetch Next From c_customers Into @v_customer_id

    While @@fetch_status = 0
    Begin

        -- ----------------------------------------------------------------
        -- Create Sales Order Header for each Customer
        -- ----------------------------------------------------------------
        Insert Into sales_order_header ...

        -- Get Sales Order Header Id
        Set @v_sales_order_header_id = scope_identity()


        -- ----------------------------------------------------------------
        -- Declare Time Log Cursor: Get the list of Time Log by customer in order to Create 
        -- ----------------------------------------------------------------
        Declare c_time_log cursor for 
        Select      time_log_id                     as time_log_id
                    , hourly_rate                   as hourly_rate
                    , cast( (cast(tl.hours as numeric(18, 5)) + (cast(tl.minutes as numeric(18, 5)) / 60) ) as numeric(18, 5))       
                                                    as total_time
                    , sku_id                        as sku_id
        From        @tmp_time_log tl
        Where       customer_id = @v_customer_id

        -- ----------------------------------------------------------------
        -- Open Cursor
        -- ----------------------------------------------------------------
        Open c_time_log

        Fetch Next From c_time_log 
        Into @v_time_log_id, @v_hourly_rate, @v_total_time, @v_sku_id

        While @@fetch_status = 0
        Begin

            -- Create Sales Order Detail for Each SO Header
            Insert Into sales_order_detail ....


            -- Get the next Cursor
            Fetch Next From c_time_log Into @v_time_log_id, @v_hourly_rate, @v_total_time, @v_sku_id
        End


        -- Close & Deallocate Cursor
        Close c_time_log
        Deallocate c_time_log


        -- Get the next Cursor
        Fetch Next From c_customers  Into @v_customer_id
    End

    -- Close & Deallocate Cursor
    Close c_customers
    Deallocate c_customers


    -- ------------------------------------------------------------------------
    -- Export Sales Order Header & Detail From DB1 to DB2
    -- ------------------------------------------------------------------------
    Exec [DB2].[dbo].[pr_import_sales_order_from_db1]


    --  
    Commit Transaction T1

End Try

Begin Catch
    -- If Error Found Then Rollback Transaction
    If @@TRANCOUNT > 0
    Begin
        -- Close & Deallocate Cursor
        Close c_customers
        Deallocate c_customers


        -- Rollback         
        Rollback Transaction T1
    End

    -- Get Error # & Error Message  
    Select  @v_error_number = ERROR_NUMBER()
            , @v_error_message_en = 'An error occurred in ' + ERROR_PROCEDURE() + ': ' + ERROR_MESSAGE()

    GOTO Step_END

End Catch

-- ------------------------------------------------------------------------------------------
-- Return: Error # & Error message
-- ------------------------------------------------------------------------------------------
STEP_END:
    Select  @v_error_number                 as error_number  
            , @v_error_message_en           as error_message_en

End
GO

【问题讨论】:

    标签: c# asp.net sql sql-server


    【解决方案1】:

    如果您在

    处遇到错误
    exec [DB2].[dbo].[pr_import_sales_order_from_db1]**  //are those asterisks there in your code
    

    那么您已经关闭并释放了 c_customers,但是您将在 catch 块中第二次调用这些关闭和释放调用,我认为这是问题所在。

    在上次评论后编辑

    保罗,

    您应该重新组织 Try 块的最后 4 行,如下所示。

    原创

    Close c_customers
    Deallocate c_customers
    
    Exec [DB2].[dbo].[pr_import_sales_order_from_db1]
    
    Commit Transaction T1
    

    修改

    Exec [DB2].[dbo].[pr_import_sales_order_from_db1]
    
    Close c_customers
    Deallocate c_customers
    
    Commit Transaction T1
    

    这样做的原因是目前的情况,如果你 CLOSE & DEALLOCATE 游标,然后在你的 DB2 SPROC 中发生错误,你将尝试 CLOSE & DEALLOCATE 游标第二次在你的 catch 块中。

    在修改/重新排列的版本中,如果一切正常,您仍然会在 COMMIT TRAN 之前关闭并释放游标,但如果 DB2 SPROC 出现问题,它将直接跳转到 catch 块和 @ catch 块中的 987654329@ 和 DEALLOCATE 将按预期工作。

    【讨论】:

    • 只是补充一点,OP 将要检查他的连接字符串正在使用的用户帐户,以查看它是否真的可以访问 DB2(和那个 proc)。我怀疑pr_import_sales_order_from_db1 失败的原因是权限问题。
    • @ChrisLively:你是对的!最初我使用 DB1 的用户在 C# 中调用 SP。所以现在,我使用用户 SA 尝试它,它工作正常,它在 DB1 和 DB2 中创建记录!!!此外,我在回滚部分保持​​关闭和 Deqallocate 光标......谢谢克里斯
    • @Paul:很高兴有帮助。虽然我不确定你在回滚部分保持​​关闭和解除分配是什么意思。您的代码需要更改,以便无论什么游标都被关闭并准确地释放一次。不多也不少。
    • @ChrisLively:我们应该总是关闭一个游标......我必须使用这种方式,因为如果在游标循环时抛出异常,它会告诉我们游标仍然打开......所以这就是为什么我 CLOSE 它并 DEALLOCATE 它......我过去遇到过这种情况!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-18
    • 1970-01-01
    • 2014-08-16
    • 1970-01-01
    相关资源
    最近更新 更多