2016-02-09 4 views
1

Я пытаюсь создать большой транзакционный инструмент, который является всем или ничего. Я ввожу около 2000 записей. Я хочу вставить первичный ключ, прочитать его обратно, а затем вставить внешний ключ в транзакцию и затем отбросить все обратно, если произошла ошибка.Первичная клавиша TransactionScope, затем вставка внешнего ключа -> Вставляет 2 строки основного ключа

PSS_InvoiceTotal Таблица имеет PK -> InvoiceTotalID

PSS_Invoices таблица имеет FK -> InvoiceTotalID

Проблема заключается в базе данных каждый раз, когда 2 Основные ключевые строки сделаны. Я запускал код без вставки внешнего ключа, и он работал нормально. Есть ли способ предотвратить создание двух строк основного ключа?

 using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required)) 
     { 
      try 
      { 
       conn.Open(); 

       foreach (var uniqueSupply in supplyList.GroupBy(a=>a.ShipTo)) 
       { 
        //reset total 
        total = 0; 

        var supplyListByShipTo = supplyList.Where(a => a.ShipTo == uniqueSupply.Key); 

        foreach (var addSupply in supplyListByShipTo) 
        { 
         total = total + addSupply.Amount; 
        } 

        StringBuilder insert_PSS_InvoiceTotal = new StringBuilder(); 

        //save total to DB 
        insert_PSS_InvoiceTotal = new StringBuilder(); 
        insert_PSS_InvoiceTotal.Append("INSERT INTO [PSS_InvoiceTotal] "); 
        insert_PSS_InvoiceTotal.Append("([InvoiceDate],[Amount]) "); 
        insert_PSS_InvoiceTotal.Append("VALUES(@DateTime, @Amount) "); 
        insert_PSS_InvoiceTotal.Append("SELECT SCOPE_IDENTITY() AS [InvoiceTotalID];"); 

        cmd = new SqlCommand(insert_PSS_InvoiceTotal.ToString(), conn); 

        cmd.Parameters.AddWithValue("@DateTime", DateTime.Now); 
        cmd.Parameters.AddWithValue("@Amount", total); 

        //ToDo: Add back in later 
        cmd.ExecuteNonQuery(); 

        SqlDataReader dr = cmd.ExecuteReader(); 
        if (dr.Read()) 
        { 
         InvoiceTotalID = Convert.ToInt32(dr["InvoiceTotalID"].ToString()); 
        } 

        dr.Close(); 

        foreach (var supply in supplyListByShipTo) 
        { 
         StringBuilder insert_PSS_Invoice = new StringBuilder(); 

         //Create the SQL command 
         insert_PSS_Invoice.Append("INSERT INTO [PSS_Invoices] "); 
         insert_PSS_Invoice.Append("([ClientDetailId],Amount],InvoiceTotalId)"); 
         insert_PSS_Invoice.Append("VALUES("); 
         insert_PSS_Invoice.Append("@Amount,@InvoiceTotalId)"); 

         cmd = new SqlCommand(insert_PSS_Invoice.ToString(), conn); 

         cmd.Parameters.AddWithValue("@Amount", 4.44); 
         cmd.Parameters.AddWithValue("@InvoiceTotalId", InvoiceTotalID); 

         //ToDo: put back in later 
         cmd.ExecuteNonQuery(); 
        } 
       } 

       //Close connection 
       conn.Close(); 

       //Commit and Dispose Transaction 
       scope.Complete(); 
       scope.Dispose(); 
      } 

      catch (Exception ex) 
      { 
       //Rollback Transaction 
       scope.Dispose(); 
       return Json(new { success = false, message = ex.ToString() }, JsonRequestBehavior.AllowGet); 
      } 
     } 
+1

Вы выполняете ту же самую команду дважды. Один раз с 'ExecuteNonQuery' и один раз с' ExecuteReader'. Достаточно использовать только «ExecuteReader». –

+0

Вы правы -> Klaus Byskov Pedersen –

ответ

0

попытка комментировать

//ToDo: Add back in later 
//cmd.ExecuteNonQuery(); 
-1

Может быть, вы можете посмотреть в использовании опции вывода команды INSERT, чтобы получить первичный ключ на выполнение вставки. Таким образом, вам не нужно его читать. Проверьте эту ссылку: https://msdn.microsoft.com/en-us/library/ms177564.aspx

Кроме того, вам может потребоваться добавить выходной параметр в свой командный объект, чтобы получить эту информацию.