2017-08-05 83 views
0

如截圖所示,我試圖將數據插入到表中。第一次迭代工作正常,但第二次迭代拋出錯誤/異常。不能使用c在循環中將數據插入到SQL Server表中

我的代碼有什麼問題?

以下是代碼。

SqlConnection sqlconn = new SqlConnection(sqlconnectionstring); 
// sqlconn.Open(); 

string InsertData = "INSERT INTO AUStagAPITestData ([TestSuite], [TestCase],[Status], [Info], [Time], [IsArchived], [DateTime]) VALUES (@TestSuite, @TestCase, @Status, @Info, @Time, @IsArchived, @DateTime)"; 

SqlCommand Insertcmd = new SqlCommand(InsertData, sqlconn); 

for (int j = 1; j < TDData.Length; j +=5) 
{ 
    sqlconn.Open(); 

    string TestSuite = TDData[j]; 
    string TestCase = TDData[j+1]; 
    string Status = TDData[j + 2]; 
    string Info = TDData[j + 3]; 
    string Time = TDData[j + 4]; 

    Insertcmd.Parameters.AddWithValue("@TestSuite", TestSuite); 
    Insertcmd.Parameters.AddWithValue("@TestCase", TestCase); 
    Insertcmd.Parameters.AddWithValue("@Status", Status); 
    Insertcmd.Parameters.AddWithValue("@Info", Info); 
    Insertcmd.Parameters.AddWithValue("@Time", Time); 
    Insertcmd.Parameters.AddWithValue("@IsArchived", "1"); 
    Insertcmd.Parameters.AddWithValue("@DateTime", DateTime.Now); 

    Insertcmd.ExecuteNonQuery(); 
    sqlconn.Close(); 
} 

enter image description here

+0

不要使用循環進行插入。改爲使用表值參數。 –

+0

你應該看看[我們可以停止使用AddWithValue()了嗎?](http://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/)並停止使用'.AddWithValue()' - 它可能會導致意想不到的和令人驚訝的結果... –

回答

1

它的抱怨已經添加:

Insertcmd.Parameters.AddWithValue("@TestSuite 

修復的方法是實例化一個新SqlCommand每次迭代:

for (int j = 1; j < TDData.Length; j +=5) 
{ 
sqlconn.Open(); 
SqlCommand Insertcmd = new SqlCommand(InsertData, sqlconn); 
string TestSuite= TDData[j]; 
+0

或更好:**創建**參數對象**一次**,在循環之前,然後在循環中**設置值** - 不會一遍又一遍地重複創建新的參數對象... –

0

嘗試移動sqlconn.Open ()& sqlconn.Close()o使用for循環並續訂sqlcommand對象。

sqlconn.Open(); 
for (int j = 1; j < TDData.Length; j += 5) 
{ 
    SqlCommand Insertcmd = new SqlCommand(InsertData, sqlconn); 
    string TestSuite = TDData[j]; 
    ... 
} 
sqlconn.Close(); 
+0

只要您需要它們就可以使用資源,移動在循環外打開就是一個例子,連接實際上並沒有打開和關閉你可以調用SqlConnection.Open。當conn字符串匹配先前使用的conn字符串時,ASP.NET從池中循環激活連接。所涉及的開銷不重要,另外,試圖「自己動手」意味着您必須承擔所有管理任務,以確保每次後續使用的連接仍處於活動狀態,這增加了複雜性和開銷。通過連接池,最佳實踐是在每次使用時打開和關閉它。 –

+0

我不同意你的看法,我們不應該在for循環中打開/關閉連接,我們可以重新使用連接。 – jerry

+0

這是個人的觀點嗎? –

0

檢查這個例子根據您的代碼:

string connectionString, queryInsert; 
string[] arrayData = new string[10]; 

connectionString = ConfigurationManager.ConnectionStrings["DbConn"].ConnectionString; 
queryInsert = @" 
    INSERT INTO AUStagAPITestData 
    (
     [TestSuite], [TestCase], [Status], [Info], [Time], [IsArchived], [DateTime] 
    ) 
    VALUES (
     @TestSuite, @TestCase, @Status, @Info, @Time, @IsArchived, @DateTime 
    ) 
"; 

using (SqlConnection connection = new SqlConnection(connectionString)) 
using (SqlCommand command = new SqlCommand(queryInsert, connection)) 
{ 
    string testSuite, testCase, status, info, time; 

    connection.Open(); 

    for (int j = 1; j < arrayData.Length; j += 5) 
    { 
     testSuite = arrayData[j]; 
     testCase = arrayData[j + 1]; 
     status = arrayData[j + 2]; 
     info = arrayData[j + 3]; 
     time = arrayData[j + 4]; 

     command.Parameters.AddWithValue("@TestSuite", testSuite); 
     command.Parameters.AddWithValue("@TestCase", testCase); 
     command.Parameters.AddWithValue("@Status", status); 
     command.Parameters.AddWithValue("@Info", info); 
     command.Parameters.AddWithValue("@Time", time); 
     command.Parameters.AddWithValue("@IsArchived", "1"); 
     command.Parameters.AddWithValue("@DateTime", DateTime.Now); 

     command.ExecuteNonQuery(); 

     // To Clear parameters 
     command.Parameters.Clear(); 
    } 
    // no need to close a disposed object since dispose will call close 
} 
0

您可以使用您的Insertcmd.Parameters.Clear()在for循環中。

1

什麼你真正應該做的是:

  • 循環過程中創建參數的對象列表一次,循環
  • 之前,只設置了

類似這樣的:

string InsertData = "INSERT INTO AUStagAPITestData ([TestSuite], [TestCase],[Status], [Info], [Time], [IsArchived], [DateTime]) VALUES (@TestSuite, @TestCase, @Status, @Info, @Time, @IsArchived, @DateTime)"; 

// put your connection and command into *USING* blocks to properly dispose of them 
using (SqlConnection sqlconn = new SqlConnection(sqlconnectionstring)) 
using (SqlCommand Insertcmd = new SqlCommand(InsertData, sqlconn)) 
{ 
    // create the parameters **ONCE** and define their datatypes 
    // I have only *guessed* what the datatypes could be - adapt as needed 
    Insertcmd.Parameters.Add("@TestSuite", SqlDbType.VarChar, 50); 
    Insertcmd.Parameters.Add("@TestCase", SqlDbType.VarChar, 50); 
    Insertcmd.Parameters.Add("@Status", SqlDbType.VarChar, 50); 
    Insertcmd.Parameters.Add("@Info", SqlDbType.VarChar, 50); 
    Insertcmd.Parameters.Add("@Time", SqlDbType.Time); 
    Insertcmd.Parameters.Add("@IsArchived", SqlDbType.Boolean); 
    Insertcmd.Parameters.Add("@DateTime", SqlDbType.DateTime); 

    sqlconn.Open(); 

    // now loop over the data and set the parameter values 
    for (int j = 1; j < TDData.Length; j +=5) 
    { 
     string TestSuite = TDData[j]; 
     string TestCase = TDData[j+1]; 
     string Status = TDData[j + 2]; 
     string Info = TDData[j + 3]; 
     string Time = TDData[j + 4]; 

     Insertcmd.Parameters["@TestSuite"].Value = TestSuite; 
     Insertcmd.Parameters["@TestCase"].Value = TestCase; 
     Insertcmd.Parameters["@Status"].Value = Status; 
     Insertcmd.Parameters["@Info"].Value = Info; 
     Insertcmd.Parameters["@Time"].Value = Time; 
     Insertcmd.Parameters["@IsArchived"].Value = true; 
     Insertcmd.Parameters["@DateTime"].Value = DateTime.Now; 

     // execute the query in the loop 
     Insertcmd.ExecuteNonQuery(); 
    } 

    sqlconn.Close(); 
} 
0

正如我在評論中寫的,我將使用帶有表值參數的存儲過程,而不是逐個插入記錄。這具有從應用程序代碼到數據庫僅進行一次往返的優點。
但是,它也有一個缺點 - 如果一行由於某種原因(例如違反約束)失敗,整個插入將失敗。

話雖如此,爲了使用表值參數,您應該首先創建一個用戶定義的表類型。請注意,我在這裏猜測列中的數據類型,你可能需要改變他們:

CREATE TYPE dbo.tt_TestData (
    [TestSuite] int, -- I'm guessing foreign keys 
    [TestCase] int, 
    [Status] int, 
    [Info] nvarchar(255), 
    [Time] time, 
    [IsArchived] bit, 
    [DateTime] datetime 
); 
GO 

後你做到這一點,您可以創建存儲過程:

CREATE PROCEDURE stp_AUStagAPITestData_Insert 
(
    @Data dbo.tt_TestData READONLY -- Note: Readonly is a must! 
) 
AS 

INSERT INTO AUStagAPITestData (
    [TestSuite], 
    [TestCase], 
    [Status], 
    [Info], 
    [Time], 
    [IsArchived], 
    [DateTime] 
) 
SELECT 
    [TestSuite], 
    [TestCase], 
    [Status], 
    [Info], 
    [Time], 
    [IsArchived], 
    [DateTime] 
FROM @Data; 
GO 

現在,執行使用ADO.Net此存儲過程,你需要創建一個數據表爲您的數據,並將其作爲SqlDbType.Structured類型的paramameter存儲過程:

using (var sqlconn = new SqlConnection(sqlconnectionstring)) 
{ 
    using (var Insertcmd = new SqlCommand("stp_AUStagAPITestData_Insert", sqlconn)) 
    { 
     // Create the data table 
     using (var dt = new DataTable()) 
     { 
      dt.Columns.Add("TestSuite", typeof(int)); 
      dt.Columns.Add("TestCase", typeof(int)); 
      dt.Columns.Add("Status", typeof(int)); 
      dt.Columns.Add("Info", typeof(string)); 
      dt.Columns.Add("Time", typeof(DateTime)); 
      dt.Columns.Add("IsArchived", typeof(bool)); 
      dt.Columns.Add("DateTime", typeof(DateTime)); 

      // Populate the data table from the TDData string array 
      for (int j = 1; j < TDData.Length; j += 5) 
      { 
       dt.Rows.Add 
       (
        TDData[j],  // TestSuite 
        TDData[j + 1], // TestCase 
        TDData[j + 2], // Status 
        TDData[j + 3], // Info 
        TDData[j + 4], // Time 
        true,   // IsArchived 
        DateTime.Now // DateTime 
       ); 
      } 

      Insertcmd.CommandType = CommandType.StoredProcedure; 
      Insertcmd.Parameters.Add("@Data", SqlDbType.Structured).Value = dt; 

      try 
      { 
       sqlconn.Open(); 
       Insertcmd.ExecuteNonQuery(); 
      } 
      catch (Exception e) 
      { 
       // Exception handling code goes here... 
      } 
     } 
    } 
} 
相關問題