2014-05-02 127 views
0

我创建了一个销售表,其插入功能无法正常工作。它显示如下错误消息“ExecuteNonQuery需要一个开放的可用连接,连接的当前状态为关闭”如果我删除了第14行的Sql关闭语句,则显示此错误消息msg “已经有一个打开的DataReader关联这个命令必须先关闭。“我的代码如下工作。我从我的产品表中检查了可用库存。如果数量订单大于产品表中的数量,则显示错误消息。否则,请继续将订单信息插入到销售表中。任何帮助表示赞赏。插入Sql功能不起作用

private void btnOrder_Click(object sender, EventArgs e) 
    { 
     int iQuantityDB; 
     int iCustomerID = Convert.ToInt32(txtCustomerID.Text); 
     int iProductID = Convert.ToInt32(txtProductID.Text); 
     decimal dPrice = Convert.ToDecimal(txtPrice.Text); 
     int iQuantity = Convert.ToInt32(txtQuantity.Text); 
     decimal dSubtotal = Convert.ToDecimal(txtSubTotal.Text); 
     decimal dGST = Convert.ToDecimal(txtGST.Text); 
     decimal dTotal = Convert.ToDecimal(txtTotal.Text); 
 string strConnectionString = @"Data Source = KK\SQLEXPRESS; Integrated Security = SSPI; Initial Catalog = JeanDB; MultipleActiveResultSets=True;"; 
     using (var sqlconn = new SqlConnection(strConnectionString)) 
     { 
      sqlconn.Open(); 
      string querySelectQuantity = @"Select Quantity from dbo.JeanProduct WHERE ProductID = @iProductID"; 
      using (var cmdOrder = new SqlCommand(querySelectQuantity, sqlconn)) 
      { 

       using (var sdRead = cmdOrder.ExecuteReader()) 
       { 
        sdRead.Read(); 
        iQuantityDB = Convert.ToInt32(sdRead["Quantity"]); 

       } 
      } 
      if (iQuantityDB > iQuantity) 
      { 
       string InsertQuery = @"INSERT INTO Sale(CustomerID, ProductID, Price, Quantity, Subtotal, GST, Total)VALUES(@iCustomerID, @iProductID, @dPrice, @iQuantity, @dSubtotal, @dGST, @Total)"; 
       using (var InsertCMD = new SqlCommand(InsertQuery, sqlconn)) 
       { 
        InsertCMD.Connection = sqlconn; 

        InsertCMD.Parameters.AddWithValue("@iCustomerID", iCustomerID); 
        InsertCMD.Parameters.AddWithValue("@iProdcutID", iProductID); 
        InsertCMD.Parameters.AddWithValue("@dPrice", dPrice); 
        InsertCMD.Parameters.AddWithValue("@iQuantity", iQuantity); 
        InsertCMD.Parameters.AddWithValue("@dSubtotal", dSubtotal); 
        InsertCMD.Parameters.AddWithValue("@dGST", dGST); 
        InsertCMD.Parameters.AddWithValue("@dTotal", dTotal); 
        InsertCMD.ExecuteNonQuery(); 


        LoadDataonTable(); 
       } 

      } 

      else 
      { 
       MessageBox.Show("no more stock"); 

      } 
      sqlconn.Close(); 

     } 

    } 
+1

为什么不使用'ExecuteReader',为什么不使用'ExecuteScalar',因为它看起来像你不想*让* sdRead'读者打开? –

回答

1

您应该将连接字符串更改为

string strConnectionString = @"Data Source = KK\SQLEXPRESS; 
           Integrated Security = SSPI; 
           Initial Catalog = JeanDB; 
           MultipleActiveResultSets=True"; 

不要关闭Reader.Read和为ExecuteNonQuery之间的连接。 您至少需要Sql Server 2005才能正常工作。

除非使用MultipleActiveResultSets键设置连接字符串,否则SqlDataReader使用的连接不能用于其他操作。当然你可以打开两个连接对象(具有相同的连接字符串),并使用一个用于SqlDataReader,另一个用来执行你的命令。

没有真正的链接到您的问题,但我建议也使用参数化查询也为您的代码的SELECT部分​​。

此外,您应该围绕一次性物品使用Using Statement以确保在出现异常情况时也能正确关闭和处理。最后,INSERT INTO中使用的语法不正确。我认为这段代码可以解释上面解释的一些观点。

string strConnectionString = @"......;MultipleActiveResultSets=True;"; 
using(SqlConnection sqlconn = new SqlConnection(strConnectionString)) 
{ 
    sqlconn.Open(); 
    string querySelectQuantity = @"Select Quantity from dbo.JeanProduct 
            WHERE ProductID = @id"; 
    using(SqlCommand cmdOrder = new SqlCommand(querySelectQuantity, sqlconn)) 
    { 
     cmdOrder.AddWithValue("@id", Convert.ToInt32(txtProductID.Text)); 
     using(SqlDataReader sdRead = cmdOrder.ExecuteReader()) 
     { 
      if(sdRead.Read()) 
      { 
       ..... 
       string InsertQuery = @"INSERT INTO Sale(SaleID, CustomerID, ProductID, 
        Price, Quantity, Subtotal, GST, Total)VALUES(@iCustomerID, 
        @iProductID, @dPrice, @iQuantity, 
        @dSubtotal, @dGST, @Total)"; 
        using(SqlCommand InsertCMD = new SqlCommand(InsertQuery, sqlconn)) 
        { 
         InsertCMD.Parameters.AddWithValue("@iCustomerID", iCustomerID); 
         .... 
         InsertCMD.ExecuteNonQuery(); 
         LoadDataonTable(); 
        } 
      } 
      else 
      { 
        MessageBox.Show("no more stock"); 
      } 
     } 
    } 
} 
1

您关闭SqlConnection读者执行/读周期后(和其他错误,你已经把读者开放,而试图执行另一个命令)。

请关闭阅读器并将连接保持为打开插入位置,或打开插入的新连接。

更妙的是,使用using处理处置的资源为你,并尽快公布范围的数据库资源,你与他们所做的,如:

using (var sqlconn = new SqlConnection(strConnectionString)) 
{ 
    sqlconn.Open(); 

    string querySelectQuantity = "Select Quantity ..."; 
    using var (cmdOrder = new SqlCommand(querySelectQuantity, sqlconn)) 
    { 
     int iQuantityDB; 
     using (var sdRead = cmdOrder.ExecuteReader()) 
     { 
      sdRead.Read(); 
      iQuantityDB = Convert.ToInt32(sdRead["Quantity"]); 
     } // Dispose reader 
     // sqlconn.Close(); <-- Don't close 
    } // cmdOrder disposed here 

    if (iQuantityDB > iQuantity) 
    { 
     string InsertQuery = "INSERT INTO ..."; 
     using var (InsertCMD = new SqlCommand(InsertQuery, sqlconn)) 
     { 
      // ... 
     } // InsertCmd disposed here 
    } 
} // Sql Connection disposed here 

这将克服许多错误,比如你有条件地关闭if分支中的命令+连接的地方。

+0

谢谢大家的帮忙。我遵循你的建议,并用“使用”改变了编码。但我仍然有错误语句“不正确的语法附近'='。”在InsertCMD.ExecuteNonQuery()的行;任何想法。我进行了调试并逐行阅读,找不到错误的地方。 – kkcoder

+0

您还需要在插入时遵循Steve的建议 - 语法为INSERT INTO Table(Col1,Col2,....)VALUES(@ Col1,@ Col2 ...)'(不是'Col1 = @ Col1')。此外,您正在列出“SaleId”列但没有值 - 值的数量必须与指定的列匹配。如果它是一个标识列,则将其从列表中删除。如果您仍然陷入困境,请在您的问题下面粘贴更新的Sql,或者提出一个全新的问题。如果你只需要从一行中读取一列值,达米恩关于ExecuteScalar vs Reader的观点也是一个很好的观点。 – StuartLC

+0

谢谢。我会创建一个新的问题。 – kkcoder