C# 如何让这个数据库交互工作?我不断地尝试,它不断抛出异常

C# 如何让这个数据库交互工作?我不断地尝试,它不断抛出异常,c#,sql,database,visual-studio,C#,Sql,Database,Visual Studio,我是一名学生。别担心,我缺乏技能目前对任何专业组织都没有影响 我现在正试图建立一个基于数据库的密码系统。有很多元素要处理,但现在我只想调用一些数据并将其插入到我的项目中 当前,我在if(dr.Read())处收到NullReferenceException 相关代码为: string strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=access.mdb"; SqlConnection

我是一名学生。别担心,我缺乏技能目前对任何专业组织都没有影响

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

当前,我在if(dr.Read())处收到NullReferenceException

相关代码为:

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


问题不在您告诉我们的线路中,而是在之前,它是由您尝试使用
SqlClient
类连接到
MS Access
数据库引起的。要进行访问,您需要使用OleDb而不是SqlClient。该错误被空的try-catch块隐藏。永远不要使用空的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块的右括号中被释放。这也会关闭连接,并在异常情况下关闭读卡器,从而简化代码

如下面的注释所述,如果查询只返回一行中的一列,则可以使用
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!");

问题不在您告诉我们的线路中,而是在之前,它是由您尝试使用
SqlClient
类连接到
MS Access
数据库引起的。要进行访问,您需要使用OleDb而不是SqlClient。该错误被空的try-catch块隐藏。永远不要使用空的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块的右括号中被释放。这也会关闭连接,并在异常情况下关闭读卡器,从而简化代码

如下面的注释所述,如果查询只返回一行中的一列,则可以使用
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!");

@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行/列,则ExecuteScalar()更好,因为ExecuteReader()提供了一个不必要的IDisposable资源。

错误的可能原因由@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行/列,则ExecuteScalar()更好,因为ExecuteReader()提供了一个不必要的IDisposable资源。

Steve的建议将我引向以下解决方案:

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);
            }
        }

Steve的建议将我引向以下解决方案:

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);
            }
        }

这更多的是评论,而不是评论。这就是问题的答案。因为这是
dr
可以
null
的唯一方法,因为OP正在吃空
catch
中的异常