C# 使用回滚在单个事务中执行两个函数

C# 使用回滚在单个事务中执行两个函数,c#,oracle,c#-4.0,datagridview,oracle11gr2,C#,Oracle,C# 4.0,Datagridview,Oracle11gr2,带有主键的订单表订单id 订单详细信息与订单表中的主键的参考完整性订单id F_in_ORDER_DATAoracle函数将从DataGridView接收数据并将其插入oracle数据库 该函数由两个insert语句组成 首先,将一条记录插入订单表,并返回表上触发器分配的主键订单id 第二个将从第一个语句返回Order\u id,并将其用作引用完整性 在order_details表中插入订单中的所有项目(DataGridView) 并保持订单明细表中所有记录的订单id相同,而订单表中的主键 注意

带有主键的订单表订单id

订单详细信息与订单表中的
主键的
参考完整性
订单id

F_in_ORDER_DATA
oracle函数将从
DataGridView
接收数据并将其插入oracle数据库 该函数由两个insert语句组成

  • 首先,将一条记录插入订单表,并返回表上触发器分配的
    主键
    订单id

  • 第二个将从第一个语句返回Order\u id,并将其用作引用完整性 在order_details表中插入订单中的所有项目(
    DataGridView
    ) 并保持订单明细表中所有记录的订单id相同,而订单表中的
    主键

  • 注意 我使用这种方法强制所有事务在一个事务中完成,所以 如果任何步骤中出现任何错误,
    rollback
    rollback
    该函数所做的所有更改 由于没有发生任何事情(一次往返交易)

    我猜解决方案可能如下,但寻找更好的方法或改进

    制作两个功能
    F_-INS_-ORDER_-DATA
    F_-INS_-ORDER_-DETAILS_-DATA

    但在这种情况下,如何在一个事务中完成所有更改

    C#代码

                string connstr = @"Data Source=orcl; User Id=user; password=pwd;";
                string insertcmdtxt = @"F_INS_ORDER_DATA";   
    
                using (OracleConnection conn = new OracleConnection(connstr))
                using (OracleCommand cmd = new OracleCommand(insertcmdtxt, conn))
                {
                    try
                    {
                        conn.Open();
    
                        cmd.CommandType = CommandType.StoredProcedure;
    
                        cmd.CommandText = insertcmdtxt;
    
                        foreach (DataGridViewRow Row in DGV_INVOICE.Rows)
                        {
                            cmd.Parameters.Clear();
    
                            cmd.Parameters.Add(":vORDER_ID", OracleDbType.Int32, ParameterDirection.ReturnValue);
    
                            cmd.Parameters.Add(new OracleParameter(":P_CUSTOMER_ID", OracleDbType.Int32)).Value     = TB_CUSTOMER_ID.Text;
                            cmd.Parameters.Add(new OracleParameter(":P_ORDER_NOTE", OracleDbType.Varchar2)).Value   = TB_ORDER_NOTE.Text;
    
                            cmd.Parameters.Add(new OracleParameter(":P_PRODUCT_ID", OracleDbType.Int32)).Value      = Row.Cells[DGV_INVOICE.Columns["DGV_PRODUCT_ID"].Index].Value;
                            cmd.Parameters.Add(new OracleParameter(":P_UNIT_PRICE", OracleDbType.Int32)).Value      = Row.Cells[DGV_INVOICE.Columns["DGV_UNIT_PRICE"].Index].Value;
                            cmd.Parameters.Add(new OracleParameter(":P_QUANTITY", OracleDbType.Int32)).Value        = Row.Cells[DGV_INVOICE.Columns["DGV_QUANTITY"].Index].Value;
                            cmd.Parameters.Add(new OracleParameter(":P_DISCOUNT", OracleDbType.Int32)).Value        = Row.Cells[DGV_INVOICE.Columns["DGV_DISCOUNT"].Index].Value;
                            cmd.Parameters.Add(new OracleParameter(":P_ORDER_STATUS", OracleDbType.Varchar2)).Value = '1';
                            cmd.Parameters.Add(new OracleParameter(":P_ITEM_NOTE", OracleDbType.Varchar2)).Value    = Row.Cells[DGV_INVOICE.Columns["DGV_ITEM_NOTE"].Index].Value;
    
                            cmd.ExecuteNonQuery();
    
                            TB_INVOICE_ID.Text = (cmd.Parameters[":vORDER_ID"].Value).ToString();
                        }                        
                    }
                    catch (Exception EX)
                    {
                        MessageBox.Show(EX.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                }
    
    Oracle功能

    CREATE OR REPLACE FUNCTION F_INS_Order_Data (P_CUSTOMER_ID     IN NUMBER,
                                                                                           P_ORDER_NOTE       IN VARCHAR2,
                                                                                           P_PRODUCT_ID        IN NUMBER,
                                                                                           P_UNIT_PRICE         IN NUMBER,
                                                                                           P_QUANTITY           IN NUMBER,
                                                                                           P_DISCOUNT           IN NUMBER,
                                                                                           P_ORDER_STATUS  IN VARCHAR2,
                                                                                           P_ITEM_NOTE         IN VARCHAR2)
       RETURN NUMBER
    IS
       VOrder_Id      NUMBER;                --ORDER_ID Filled by trigger
       vCreated_by   VARCHAR2 (64)         := 'SYSTEM';
       vCreated_On   DATE                        := SYSDATE;
    
       sql_stmt           VARCHAR2 (4000);
       ERR_CODE      VARCHAR2(64);
       ERR_MSG       VARCHAR2(1024);
    
    BEGIN
    
        SAVEPOINT Setp1;
    
        sql_stmt := 'INSERT INTO orders (ORDER_ID,
                                                              CUSTOMER_ID,
                                                              NOTES,
                                                              CREATED_BY,
                                                              CREATED_ON)
                                                VALUES (NULL,                       --ORDER_ID Filled by trigger
                                                              :PCUSTOMER_ID,    --CUSTOMER_ID
                                                              :POrderNote,            --NOTES
                                                              :PCREATED_BY,       --CREATED_BY
                                                              :PCREATED_ON)     --CREATED_ON
                          RETURNING ORDER_ID INTO :vORDER_ID';
    
        EXECUTE IMMEDIATE sql_stmt USING P_CUSTOMER_ID,
                                                                       P_ORDER_NOTE,
                                                                       vCreated_by,
                                                                       vCreated_ON
                          RETURNING INTO vORDER_ID;
    
        --DBMS_OUTPUT.PUT_LINE (sql_stmt);    /* For Testing Purpose */
    
    
        sql_stmt:='INSERT INTO ORDER_DETAILS (ORDER_ID,
                                                                               PRODUCT_ID,
                                                                               UNIT_PRICE,
                                                                               QUANTITY,
                                                                               DISCOUNT,
                                                                               ORDER_STATUS,
                                                                               NOTES,
                                                                               CREATED_BY,
                                                                               CREATED_ON)
                                                               VALUES ( :PvORDER_ID,              --ORDER_ID,
                                                                               :PPRODUCT_ID,          --PRODUCT_ID
                                                                               :PUNIT_PRICE,           --UNIT_PRICE
                                                                               :PQUANTITY,             --QUANTITY
                                                                               :PDISCOUNT,             --DISCOUNT
                                                                               :PORDER_STATUS,    --ORDER_STATUS
                                                                               :PItem_Note,                 --NOTES
                                                                               :PCREATED_BY,          --CREATED_BY
                                                                               :PCREATED_ON         --CREATED_ON
                                                                              )';
    
        EXECUTE IMMEDIATE sql_stmt USING vORDER_ID,
                                                                       P_PRODUCT_ID,
                                                                       P_UNIT_PRICE,
                                                                       P_QUANTITY,
                                                                       P_DISCOUNT,
                                                                       P_ORDER_STATUS,
                                                                       P_ITEM_NOTE,
                                                                       vCreated_by,
                                                                       vCreated_On;
    
       --DBMS_OUTPUT.PUT_LINE (sql_stmt);    /* For Testing Purpose */
    
       RETURN (VOrder_Id);
    
    EXCEPTION WHEN OTHERS THEN 
    
        ROLLBACK TO Setp1;
    
        ERR_CODE := SQLCODE;
        ERR_MSG := SUBSTR(SQLERRM, 1, 1024);
    
        sql_stmt := F_INS_ERROR_LOG(SYSDATE,                        --P_ERROR_TIME,
                                                           vCreated_by,                    --P_USER_ID,
                                                           'F_INS_Order_Data',      --P_PROGRAM_UNIT,
                                                           NULL,                              --P_ERROR_LOCATION,
                                                           NULL,                             --P_KEY_DATA_DESC,
                                                           ERR_CODE,                    --P_ERROR_CODE,
                                                           ERR_MSG);                    --P_ERROR_MSG)';
    
    RETURN -1;
    
    END F_INS_Order_Data;
    /
    
    将中的单独功能更新为两个功能

    顺序数据的第一个函数

    CREATE OR REPLACE FUNCTION F_INS_ORDER_DATA (P_CUSTOMER_ID     IN NUMBER,
                                                 P_ORDER_NOTE       IN VARCHAR2,
                                                 P_CREATED_BY         IN VARCHAR2)
       RETURN NUMBER
    IS
       vORDER_ID    NUMBER;
       vCreated_On   DATE:= SYSDATE;
    
       sql_stmt      VARCHAR2 (4000);
       ERR_CODE      VARCHAR2(64);
       ERR_MSG       VARCHAR2(1024);
    
    BEGIN
    
        SAVEPOINT Setp1;
    
        sql_stmt := 'INSERT INTO ORDERS (ORDER_ID,
                                         CUSTOMER_ID,
                                         NOTES,
                                         CREATED_BY,
                                         CREATED_ON)
                                 VALUES (NULL,              --ORDER_ID Filled by trigger
                                         :PCUSTOMER_ID,     --CUSTOMER_ID
                                         :PORDER_NOTE,      --NOTES
                                         :PCREATED_BY,      --CREATED_BY
                                         :PCREATED_ON)      --CREATED_ON
                              RETURNING ORDER_ID INTO :vORDER_ID';
    
        EXECUTE IMMEDIATE sql_stmt USING P_CUSTOMER_ID,
                                         P_ORDER_NOTE,
                                         P_CREATED_BY,
                                         vCreated_ON
                          RETURNING INTO vORDER_ID;
    
        DBMS_OUTPUT.PUT_LINE (sql_stmt);    /* For Testing Purpose */
    
       RETURN (vOrder_Id);
    
    EXCEPTION WHEN OTHERS THEN 
    
        ROLLBACK TO Setp1;
    
        ERR_CODE := SQLCODE;
        ERR_MSG := SUBSTR(SQLERRM, 1, 1024);
    
        sql_stmt := F_INS_ERROR_LOG(SYSDATE,         --P_ERROR_TIME,
                                    P_CREATED_BY,                      --P_USER_ID,
                                    'F_INS_ORDER_DATA',                --P_PROGRAM_UNIT,
                                    'P_CUSTOMER_ID || vORDER_ID ',     --P_ERROR_LOCATION,
                                     P_CUSTOMER_ID||'/'||vORDER_ID,    --P_KEY_DATA_DESC,
                                     ERR_CODE,                         --P_ERROR_CODE,
                                     ERR_MSG);                         --P_ERROR_MSG)';
    
    RETURN -1;
    
    END F_INS_ORDER_DATA;
    /
    
    第二个函数的顺序数据详细信息

    CREATE OR REPLACE FUNCTION F_INS_ORDER_DATA_DETAILS (P_ORDER_ID             IN NUMBER,
                                                         P_PRODUCT_ID        IN NUMBER,
                                                         P_UNIT_PRICE         IN NUMBER,
                                                         P_QUANTITY           IN NUMBER,
                                                         P_DISCOUNT           IN NUMBER,
                                                         P_ORDER_STATUS  IN VARCHAR2,
                                                         P_ITEM_NOTE         IN VARCHAR2,
                                                         P_CREATED_BY        IN VARCHAR2)
       RETURN NUMBER
    IS
       vCreated_On   DATE:= SYSDATE;
    
       sql_stmt           VARCHAR2 (4000);
       ERR_CODE      VARCHAR2(64);
       ERR_MSG       VARCHAR2(1024);
    
    BEGIN
    
        SAVEPOINT Setp1;
    
        sql_stmt:='INSERT INTO ORDER_DETAILS (ORDER_ID,
                                              PRODUCT_ID,
                                              UNIT_PRICE,
                                              QUANTITY,
                                              DISCOUNT,
                                              ORDER_STATUS,
                                              NOTES,
                                              CREATED_BY,
                                              CREATED_ON)
                                      VALUES (:PvORDER_ID,         --ORDER_ID,
                                              :PPRODUCT_ID,        --PRODUCT_ID
                                              :PUNIT_PRICE,        --UNIT_PRICE
                                              :PQUANTITY,          --QUANTITY
                                              :PDISCOUNT,          --DISCOUNT
                                              :PORDER_STATUS,      --ORDER_STATUS
                                              :PItem_Note,         --NOTES
                                              :PCREATED_BY,        --CREATED_BY
                                              :PCREATED_ON         --CREATED_ON
                                              )';
    
        EXECUTE IMMEDIATE sql_stmt USING P_ORDER_ID,
                                         P_PRODUCT_ID,
                                         P_UNIT_PRICE,
                                         P_QUANTITY,
                                         P_DISCOUNT,
                                         P_ORDER_STATUS,
                                         P_ITEM_NOTE,
                                         P_CREATED_BY,
                                         vCreated_On;
    
       DBMS_OUTPUT.PUT_LINE (sql_stmt);    /* For Testing Purpose */
    
       RETURN (P_ORDER_ID);
    
    EXCEPTION WHEN OTHERS THEN 
    
        ROLLBACK TO Setp1;
    
        ERR_CODE := SQLCODE;
        ERR_MSG := SUBSTR(SQLERRM, 1, 1024);
    
        sql_stmt := F_INS_ERROR_LOG(SYSDATE,                       --P_ERROR_TIME,
                                    P_CREATED_BY,                  --P_USER_ID,
                                    'F_INS_ORDER_DATA_DETAILS',    --P_PROGRAM_UNIT,
                                    'P_ORDER_ID',                  --P_ERROR_LOCATION,
                                     P_ORDER_ID,                   --P_KEY_DATA_DESC,
                                     ERR_CODE,                     --P_ERROR_CODE,
                                     ERR_MSG);                     --P_ERROR_MSG)';
    
    RETURN -1;
    
    END F_INS_ORDER_DATA_DETAILS;
    /
    
  • 除非函数中有显式的commit/rollback语句,否则每个调用都应该在一个事务中发生

  • 因为你要打多个电话。。您需要确保连接的
    自动提交功能已关闭。并手动执行提交

  • 您不需要
    executeimmediate
    语句,。。您只需将普通的
    INSERT
    与绑定变量一起使用即可

  • 因为您为每个订单\ u详细信息记录调用此函数。。首先检查父订单记录是否存在。。并仅在未插入时插入