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

时间:2017-01-24 10:26:34

标签: c# oracle c#-4.0 datagridview oracle11gr2

订单表包含Primary Key Order_id

Order_details与referential integrity Order_id 一起发送到订单表中的Primary Key

F_INS_ORDER_DATA oracle函数将从DataGridView重新获取数据并将其插入Oracle数据库 该函数由两个插入语句

组成
  1. 第一个会在Order表中插入一条记录并返回由表格上的触发器分配的primary key Order_id

  2. 第二个将从第一个语句返回 Order_id 并将其用作参照完整性 在order_details表中插入订单中的所有项目(DataGridView) 保持 order_id 对于Order_details表中的所有记录都是相同的,而在订单表中primary key

  3. 注意 我正在使用该方法强制所有事务在一个事务中完成 如果任何步骤中的任何错误都符合rollback rollback将由函数完成的所有更改 没有任何反应(一次往返交易)

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

    制作两个函数F_INS_ORDER_DATAF_INS_ORDER_DETAILS_DATA

    但在这种情况下,如何在 ONE SINGLE TRANSACTION 中完成所有更改???

    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;
    /
    

    将单独的功能更新为两个功能

    第一个功能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;
    /
    

    第二个功能F_INS_ORDER_DATA_DETAILS

    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;
    /
    

1 个答案:

答案 0 :(得分:0)

  1. 除非你的函数中有明确的commit / rollback语句,否则每次调用都应该在一个事务中发生。

  2. 因为您正在拨打多个电话..您需要确保已关闭autocommit以进行连接。并手动提交

  3. 你不需要execute immediate语句,你可以使用带有绑定变量的普通INSERT

  4. 因为您为每个ORDER_DETAILS记录调用此函数..首先检查父ORDER记录是否存在..并且仅在不存在时插入它。