2017-01-23 108 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