2017-10-12 67 views
3

我正在學校項目中工作,並且無法將一段數據從Access數據庫轉換爲可傳遞給C#中第二個窗體的字符串。我知道與數據庫的連接正在工作,並且我在其中引用了正確的表來獲取信息,所以我不確定我在做什麼錯誤。它不會在代碼中顯示任何錯誤,但是每次運行應用程序時,都會崩潰,因爲它無法從string accountnumber = reader["Account_Number"].ToString();行的字符串的數據庫中找到值。有什麼我做錯了嗎?C#無法將數據庫值轉換爲字符串

OleDbCommand command = new OleDbCommand(); 
     command.Connection = connection; 
     command.CommandText = "select * from User_Info where Username='" +txt_Username.Text+ "' and Password='" +txt_Password.Text+ "'"; 
     OleDbDataReader reader = command.ExecuteReader(); 
     int count = 0; 
     string accountnumber = reader["Account_Number"].ToString(); 
     while (reader.Read()) 
     { 
      count = count+1; 
     } 
     if (count == 1) 
     { 
      MessageBox.Show("Login Successful!", "Success!"); 
      connection.Close(); 
      connection.Dispose(); 
      this.Hide(); 
      User_Account_Screen UAS = new User_Account_Screen(); 
      UAS.Number = accountnumber; 
      UAS.ShowDialog(); 
+4

你真的應該使用參數化查詢。做'X ='+ someTextBox.Text +'''總是一件壞事 –

+0

什麼是數據庫中的帳號列?它必須是Account_Number。 –

+0

你能分享三個確切的錯誤信息嗎?你需要從數據庫返回確切的一行,你應該把所有的代碼放在'if(reader.Read()){string accountNumber = ......; MessageBox.Show .....等等你不需要'count'變量。 –

回答

8
  1. 嘗試,除非你有不重用連接。主要原因是您通常希望儘快關閉連接,並且如果您有多個事件/操作可能在數據驅動的同時發生,它將在以後防範可能的競爭條件。
  2. 儘快關閉你的連接,這樣你就沒有公開的外部資源。
  3. 確保1和2出現在使用塊中包裝您的IDisposable類型。
  4. 在查詢中始終使用參數而不是字符串連接。它防範SQL注入(不適用於MS Access),並確保您永遠不會遇到包含轉義字符的字符串問題。
  5. 有關MS Access和參數的注意事項:佔位符通常由?字符指定,並且取決於位置。 這很關鍵,你不能依賴參數的名字。如果您在該集合中具有3個參數的參數集合,那麼這些參數在查詢中必須以相同的順序出現。
  6. 我注意到你可能有密碼爲純文本,從不以純文本存儲密碼!而是存儲密碼的散列。要查看密碼是否與輸入的登錄哈希上的用戶提供的密碼相匹配,然後將該哈希與存儲的哈希進行比較以查看它們是否相同。使用安全密碼散列算法,如pbkdf2,scryptbcrypt
  7. 要查看一行是否存在或僅返回一個值,您還可以使用帶空檢查的ExecuteScalar,因爲如果沒有記錄返回,它將返回null。我修改了代碼,使用ExecuteScalar返回accountnumber。我還將括號中的列名括在括號內,當列名中的字符超出a-z和0-9範圍時,這是很好的做法。
  8. 如果您想要返回數據並使用數據讀取器讀取數據,請不要使用*作爲回報。改爲指定您的列名稱。這將防止你的代碼對模式的變化,比如添加列或改變列順序。

這裏是更新的代碼。

string accountnumber = null; 

using(OleDbConnection connection = new OleDbConnection(/*add your connection string here*/)) 
using(OleDbCommand command = new OleDbCommand("select [Account_Number] from User_Info where Username = ? AND Password = ?", connection)) 
{ 
    command.Parameters.Add(new OleDbParameter("@username", OleDbType.VarChar)).Value = txt_Username.Text; 
    command.Parameters.Add(new OleDbParameter("@password", OleDbType.VarChar)).Value = txt_Password.Text; 

    connection.Open(); 
    accountnumber = command.ExecuteScalar() as string; 
} 

if (accountnumber != null) 
{ 
    MessageBox.Show("Login Successful!", "Success!"); 
    this.Hide(); 
    User_Account_Screen UAS = new User_Account_Screen(); 
    UAS.Number = accountnumber; 
    UAS.ShowDialog(); 
} 
+1

@maccettura - 我在回答中添加了另一個註釋,並解釋了有關ms訪問權限和參數的信息(請參閱第5項)。 – Igor

+0

好吧,我知道它是如何使用文本字段作爲參數的,但我沒有看到訪問中的Account_Number字段如何轉換爲accountnumber字符串。我對編碼非常陌生,所以如果我錯過了一些明顯的東西,請原諒我。 – steven727

+0

IDisposable上+1。更進一步的是使用System.Data.Common類型/ DbProviderFactory,而不是對任何數據提供者特定的對象進行硬編碼。 –

-4

修正你的代碼:

OleDbCommand command = new OleDbCommand(); 
    command.Connection = connection; 
    command.CommandText = "select * from User_Info where Username='" +txt_Username.Text+ "' and Password='" +txt_Password.Text+ "'"; 
    OleDbDataReader reader = command.ExecuteReader(); 
    int count = 0; 
    string accountnumber = ""; 
    while (reader.Read()) 
    { 
     accountnumber = reader["Account_Number"].ToString(); 
     count = count+1; 
    } 
    if (count == 1) 
    { 
     MessageBox.Show("Login Successful!", "Success!"); 
     connection.Close(); 
     connection.Dispose(); 
     this.Hide(); 
     User_Account_Screen UAS = new User_Account_Screen(); 
     UAS.Number = accountnumber; 
     UAS.ShowDialog(); 
相關問題