2017-01-23 2 views
0

Я пытаюсь читать данные из DataGridView и вставлять их в базу данных. Все работает нормально, когда одна запись находится в DataGridView, но когда есть более одной записи в DataGridView, я получил только одну запись и все другие записи не были вставлены в базу данных.Только одна запись, вставленная в базу данных Oracle из 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; 
/
+0

Вы proc добавляет ORDER и ORDER_DETAILS для каждого вызова, но вы хотите, чтобы ORDER один раз, поэтому вам нужно будет изменить свою логику. Вы можете переместить свой 'TB_INVOICE_ID.Text =' внутри цикла после вызова 'ExecuteNonQuery()', тогда, если он имеет значение, отправьте его в качестве параметра и измените свой proc для проверки, если он передан или null. В противном случае сделайте 2 procs (Add_Order, Add_Order_Details). –

+0

@SteveGreene Я использовал одну функцию, чтобы заставить Rollback отменить все изменения в случае любой ошибки, чтобы избежать сомнительных транзакций и риск неполных транзакций ... если я сделаю две функции в качестве предложения, то как я могу откатить все сделанные изменения по первой и второй функции? и как сделать C# выполнять обе функции в одной транзакции? – sam

+0

Не уверен в Oracle, когда задействованы триггеры. Вы можете выбрать первый вариант и вернуть идентификатор заказа, когда он будет создан, а затем передать это на 2-й и последующие итерации. Измените логику в proc, чтобы только вставить порядок, когда он не передан (null). –

ответ

0

Это не обязательно проблема, но. cmd.Parameters.Add (": vORDER_ID", OracleDbType.Int32, ParameterDirection.ReturnValue); Вы не используете orderid в своем proceuder, и вы передаете его.

Во-вторых, Является ли foreach фактически циклом для каждой строки данных? Вы не предоставили достаточно деталей, чтобы помочь вам отладить это.

В-третьих, проверьте способ выполнения запроса. Я не думаю, что он собирается вернуть vorder_id ExecuteNonQuery()

Наконец, vorderid будет изменяться для каждой вставленной записи, и текст будет показывать только последний вставленный vorderid.

+0

'cmd.Parameters.Add (": vORDER_ID ", OracleDbType.Int32, ParameterDirection.ReturnValue);' out параметр, возвращаемый функцией Я думаю, что цикл foreach через 'datagridview', потому что я добавляю' MessageBox.Show (DGV_INVOICE.RowCount .ToString()); 'перед' ExecuteNonQuery(); 'и он отображается в соответствии с номером записи в' datagridview' для последнего момента, почему у меня есть две таблицы, первая таблица имеет Order_ID как первичный ключ и его ссылочная целостность ко второй таблице order_details – sam

+0

, наконец, я не понимаю, что вы говорите о проверке метода выполнения запроса очень четко, но когда я вызываю функцию с помощью toad, чтобы проверить ее return order_id, и еще одна причина, которая доказывает, что после он вставляет одну запись, которую возвращает orderid для интерфейса – sam