2017-01-23 104 views
0

我想从DataGridView读取数据并将其插入到数据库中。当一条记录在DataGridView中时,一切正常,但当DataGridView中有多条记录时,我只插入一条记录,并且所有其他记录都未插入到数据库中。只有一条记录从datagridview插入Oracle数据库

我已附加了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; 
/
+0

您proc已经添加在每次调用一个ORDER和ORDER_DETAILS,但你只想要的顺序一次,所以你需要改变你的逻辑。在ExecuteNonQuery()调用之后,你可以在循环内部移动你的'TB_INVOICE_ID.Text =',然后如果它有一个值作为参数发送它并且改变你的proc来测试它是否被传入或者为null。否则,使2个过程(Add_Order,Add_Order_Details)。 –

+0

@SteveGreene我使用了一个函数来强制回滚以回滚所有的更改以避免任何错误,以避免不确定的交易和不完整交易的风险......如果我提出两个函数作为我们的建议,那么我如何能够回滚所有更改通过第一和第二功能? 以及如何使c#在一个事务中同时执行两个函数? – sam

+0

在Oracle中涉及触发器时不确定。您可以选择第一个选项,并在创建时返回Order ID,然后在第二次和后续迭代中传递该ID。将proc中的逻辑更改为仅在未传入时插入顺序(空)。 –

回答

0

这不一定是问题,但。 cmd.Parameters.Add(“:vORDER_ID”,OracleDbType.Int32,ParameterDirection.ReturnValue); 你没有在你的程序中使用orderid,并且你正在通过它。

其次, foreach是否实际上循环每个数据行?您尚未提供足够的详细信息来帮助您进行调试。

三,检查查询执行方法。我不认为它会返回一个被vorder_id ExecuteNonQuery()

最后,vorderid是要改变插入的每个记录和文字只会显示最后插入的vorderid。

+0

'cmd.Parameters.Add( “:vORDER_ID”,OracleDbType.Int32,ParameterDirection.ReturnValue);'从函数返回 OUT参数我想foreach循环通过'datagridview'因为我加'MessageBox.Show(DGV_INVOICE.RowCount '; ExecuteNonQuery();'之前,并且它出现在与'datagridview'中的记录数相对应的最后一点,即为什么我有两个表第一个表的Order_ID为primary关键和它的参考完整性第二表order_details – sam

+0

最后我不明白你说的检查查询执行方法非常清楚,但当我调用函数使用蟾蜍来测试它的返回order_id和另一个原因,证明后它插入一条它返回orderid到接口的记录 – sam