2011-12-21 111 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