【发布时间】:2017-01-23 18:51:08
【问题描述】:
我正在尝试从DataGridView 读取数据并将其插入数据库。当DataGridView 中有一条记录时,一切正常,但是当DataGridView 中有不止一条记录时,我只插入了一条记录,而所有其他记录都没有插入数据库。
我已附上Oracle函数代码以获取更多详细信息。
我认为功能引起的问题,因为第一个table order 应该有一个记录,而子table order_details 应该有购买项目的列表。所以函数执行一次然后因为第一个table (Order)上的主键异常而停止。
我不知道这是否正确,但如果正确,那么如何解决并保持事情发生在一个事务中,以便所有事务都会成功,或者它会回滚之前已经完成的所有事情?
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, "حدث خطاء", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
功能代码
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;
/
【问题讨论】:
-
您在每次调用时都会添加一个 ORDER 和 ORDER_DETAILS,但您只需要一次 ORDER,因此您需要更改您的逻辑。您可以在
ExecuteNonQuery()调用之后将您的TB_INVOICE_ID.Text =移动到循环内,然后如果它有一个值将其作为参数发送并更改您的 proc 以测试它是传入还是 null。否则,制作 2 个 proc(Add_Order、Add_Order_Details)。 -
@SteveGreene 我使用了一个函数来强制 Rollback 在出现任何错误的情况下回滚所有更改,以避免不确定事务和不完整事务的风险......如果我按照我们的建议执行两个函数,那么如何我能够回滚第一个和第二个函数所做的所有更改吗?以及如何让 c# 在一个事务中执行这两个函数?
-
在 Oracle 中不确定何时涉及触发器。您可以选择第一个选项并在创建时返回 Order Id,然后在第二次和后续迭代中传递它。将proc中的逻辑更改为仅在未传入(null)时插入订单。
标签: c# datagridview oracle11gr2