如何使此数据库交互工作?我一直在努力,它不断抛出异常

时间:2014-10-25 06:46:01

标签: c# sql database visual-studio

我是学生。别担心,我缺乏技能目前不会对任何专业组织造成损害。

我现在正试图建立一个基于数据库的密码系统。还有很多元素要做,但是现在我只想调用一些数据并将其插入到我的项目中。

目前我在if(dr.Read())

获取NullReferenceException

相关代码将是:

       string strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=access.mdb";
    SqlConnection conn;
    SqlCommand cmd;
    SqlDataReader dr;
    DataTable dt;

        if (e.KeyCode == Keys.Enter)
        {
            e.Handled = true;
            e.SuppressKeyPress = true;

            try
            {
                conn = new SqlConnection(strConnectionString);
                cmd = new SqlCommand("select PASSWORD from regulate where NAME = @ID", conn);
                cmd.Parameters.AddWithValue("@ID", txtName.Text);
                conn.Open();
                dr = cmd.ExecuteReader();
            }
            catch
            { }
            if (dr.Read())
            {
                txtVaries.Text = dr["PASSWORD"].ToString();
            }
            conn.Close();

            if (txtVaries.Text == txtPW.Text)
            {
                tabControl1.TabPages.Remove(tabPW);
                tabControl1.TabPages.Remove(tabMain);
                tabControl1.TabPages.Insert(0, tabEdit);
            }

3 个答案:

答案 0 :(得分:6)

问题不在于您告诉我们的问题,而是之前的问题是由于您尝试使用SqlClient类连接到MS-Access数据库。对于Access,您需要使用OleDb而不是SqlClient。空的try catch块隐藏了该错误。永远不要使用空的挡块,除非真正微不足道的情况可以在不影响程序工作的情况下恢复。

string strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=access.mdb";
if (e.KeyCode == Keys.Enter)
{
    e.Handled = true;
    e.SuppressKeyPress = true;

    using(OLeDbConnection = conn = new OleDbConnection(strConnectionString))
    using(OleDbCommand cmd = new SqlCommand("select [PASSWORD] from regulate where NAME = @ID", conn);
    {
            cmd.Parameters.AddWithValue("@ID", txtName.Text);
            conn.Open();
            using(OleDbDataReader dr = cmd.ExecuteReader())
            {
                 ......... read your data .....
            }
     }
 }

请注意,我已将PASSWORD一词放在方括号内,PASSWORD是Access中的保留关键字,当您在sql命令文本中使用它时需要消除歧义

要看的另一件事是using statement。通过这种方式,您的连接,命令和阅读器将被释放,并且它们使用的资源将在使用块的右括号中释放。这也关闭了连接和读者也可以在例外的情况下简单地使用你的代码。

如下面Mr. Damith中的评论中所述,可以使用ExecuteScalar而非ExecuteReader执行仅从一行返回一列的查询。 ExecuteScalar对于性能更好,因为它不构造OleDbDataReader对象,使对象保持忙碌状态,直到关闭为止。它只返回请求的单个值但是你需要谨慎,因为如果查询没有找到任何匹配where子句的用户,则返回值将为null

....
cmd.Parameters.AddWithValue("@ID", txtName.Text);
conn.Open();
object result = cmd.ExecuteScalar();
if(result != null)
    txtVaries.Text = result.ToString();
else
    MessageBox.Show("No user found!");

答案 1 :(得分:0)

@Steve在SqlClient中使用OleDb连接字符串来回答您的错误的可能原因。我想指出一个整体方法。无论你使用哪个ADO提供程序,你的一个问题是你的空catch块是一个例外的pac-man,它会在没有报告或重新抛出的情况下吃掉任何错误。

然后,可能没有满足dr.Read()的前提条件,但即使连接抛出异常,您仍然会调用dr.Read()。你可以在那一行找到一个空读者。

让我们假设您的用户输入明文密码,然后您应该对其进行哈希处理,并与数据库中的单向哈希进行比较。

相反,代码的一般结构应该是:

try {
   using(var conn = new OleDbConnection(...)) {
      using(var command = new OleDbCommand("SELECT id, password FROM users WHERE username = ...", conn)) {
         conn.Open();
         using(var reader = command.ExecuteReader(...)) {
            if(reader.Read()) {
               var user = new User {
                  Id = reader.GetInt32(0), PasswordHash = reader.GetString(1)
               };
               if(User.SHA2Hash(loginPass) == user.PasswordHash)
                  return user;
               else
                  return null;  // or throw security exception
            }
         }
      }
   }
}
catch(Exception ex) {
   Logger.Error(ex);  // REPORT ERROR! DONT EAT IT
   throw new SecurityException("Login exception", ex);
}

重要的想法是使用块来为IDisposable资源在失败或成功时正确处理。

请注意,如果您编写查询以使其返回单个值,则可以简化,但我从不对登录代码执行操作,通常我会使用reader返回包含各种字段的用户记录。如果你知道你的查询将返回1行/ col,那么ExecuteScalar()会更好,因为ExecuteReader()会分配一个不必要的IDisposable资源。

答案 2 :(得分:0)

史蒂夫的建议引导我找到以下解决方案:

if (e.KeyCode == Keys.Enter)
{
e.Handled = true;
e.SuppressKeyPress = true;

string strConnection = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=access.mdb";
     string strCommand = "SELECT PASSWORD FROM regulate where NAME=@ID";
        OleDbConnection conn = new OleDbConnection(strConnection);
        OleDbCommand com = new OleDbCommand(strCommand, conn);
        OleDbDataReader dr;
        com.Parameters.AddWithValue("@ID", txtName.Text);
conn.Open();
        dr = com.ExecuteReader();
        if (dr.Read())
        { 
            txtVaries.Text = dr["PASSWORD"].ToString();

        }
        conn.Close();

            if (txtVaries.Text == txtPW.Text)
            {
                tabControl1.TabPages.Remove(tabPW);
                tabControl1.TabPages.Remove(tabMain);
                tabControl1.TabPages.Insert(0, tabEdit);
            }
        }