C# 使用回滚在单个事务中执行两个函数
带有主键的订单表订单id 订单详细信息与订单表中的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
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详细信息记录调用此函数。。首先检查父订单记录是否存在。。并仅在未插入时插入