2011-12-21 96 views
2

我正在设计一个数据库应用程序,并有一个表格填充来自数据库的数据。如果用户双击表单上的任何文本框,则可以使用输入框更改该值,然后执行以下代码更新数据库。SqlCommand.ExecuteNonQuery()不会更新我的数据库

private void ProcessChanges(string strField, string strCurrentValue) 
    { 
     //...Connect To Database...// 

     string strCaseNo = txtCaseNo.Text; 
     string strConnect = BuildConnectionString(); 
     SqlConnection linkToDB = new SqlConnection(strConnect); 
     linkToDB.Open(); 

     //...Request User Input New Value...// 

     string strMessage = "Enter ammended details and click OK," + Environment.NewLine + 
           "or click Cancel to exit."; 
     string strInput = Interaction.InputBox(strMessage, "Case Details", strCurrentValue); 

     //...Send User Input to Database...// 

     string commandText = "UPDATE tblCases SET @FieldVal = @InputVal WHERE CaseNo = @CaseNoVal;"; 
     SqlCommand sqlCom = new SqlCommand(commandText, linkToDB); 
     sqlCom.Parameters.Add("@FieldVal", SqlDbType.Text); 
     sqlCom.Parameters.Add("@InputVal", SqlDbType.Text); 
     sqlCom.Parameters.Add("@CaseNoVal", SqlDbType.VarChar); 
     sqlCom.Parameters["@FieldVal"].Value = strField; 
     sqlCom.Parameters["@InputVal"].Value = strInput; 
     sqlCom.Parameters["@CaseNoVal"].Value = strCaseNo; 
     int intQuery = sqlCom.ExecuteNonQuery(); 
     MessageBox.Show(intQuery.ToString()); 
    } 

问题是数据库根本没有更新。我知道连接是好的,因为在我的应用程序中使用了相同的ConnectionStringBuilder。我还在末尾添加了消息框,告诉我ExecuteNonQuery()的返回值是'1',因此表示行已更新。然而,我的数据库没有任何变化,现在它真的让我很烦。

+0

请原谅我,如果这是一个愚蠢的问题,但你100%确定你的数据库没有刷新,你可能正在看缓存值? – KingCronus 2011-12-21 12:29:07

回答

7

您不能使用变量作为列名称。你必须构建你的sql字符串,将列名嵌入到字符串中。

string commandText = 
    "UPDATE tblCases SET [" + strField + "] = @InputVal WHERE CaseNo = @CaseNoVal;" 

但是,您必须检查SQL注入攻击的值为strField

+1

+1 OP的代码只是做了变量赋值,并没有更新任何内容。 – 2011-12-21 12:30:13

+0

@MartinSmith:但是不应该给出类似的sql错误:*变量不是decalared *? – Jan 2011-12-21 12:30:56

+0

否,因为它们传入了该名称的参数。我应该说上面的参数分配。 – 2011-12-21 12:31:44

0

@Jan有它。不过顺便说一句,你真的应处置或关闭您的SqlConnection,从MSDN:

如果的SqlConnection超出范围,它不会被关闭。因此,您必须通过调用Close或Dispose来显式关闭连接。 Close和Dispose在功能上是等效的。如果连接池值Pooling设置为true或yes,则将底层连接返回到连接池。另一方面,如果将Pooling设置为false或否,则与服务器的底层连接实际上是关闭的。

using构建体存在于C#只是这样一件事:

using (SqlConnection linkToDB = new SqlConnection(strConnect) 
{ 
    // use the linkToDb here 
} 
1

如果更新的CommandText线如下:

string commandText = "UPDATE tblCases SET @FieldVal = " + strField + " WHERE CaseNo = @CaseNoVal;"; 

和删除线

sqlCom.Parameters.Add("@FieldVal", SqlDbType.Text); 
sqlCom.Parameters["@FieldVal"].Value = strField; 

请注意,尽管如此做对于这种情况,您可能会打开自己的SQL注入攻击,因此您需要真正信任提供给此方法的值或做一些工作以确保任何strField值都不包含实际的SQL语句。

例如如果strField包含;[some malicious SQL here],那么将使用分配给连接的用户的权限运行。

+0

感谢您的警告 - 我不会想到这一点。然而,在这个特定的应用程序 - 用户无权访问字段名称。该字段的名称(strfield)由调用ProcessChanges()的控件发送。 – PJW 2011-12-21 13:52:45