如何使此数据库交互工作?我一直在尝试,但它总是抛出异常
本文关键字:抛出异常 数据库 何使此 交互 互工作 我一直在 | 更新日期: 2023-09-27 18:27:57
我是一名学生。别担心,我的技能不足目前对任何专业组织都没有损害。
我现在正试图建立一个基于数据库的密码系统。还有很多元素要做,但现在我只想调用一些数据并将其插入到我的项目中。
目前我在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);
}
问题不在您告诉我们的行中,而是在之前,它是由您尝试使用SqlClient
类连接到MS-Access
数据库引起的。对于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语句。通过这种方式,您的连接、命令和读取器被释放,并且它们使用的资源在using块的右大括号处被释放。这也会关闭连接和读取器,以防出现异常,只需大量修改代码。
正如Damith先生在下面的评论中所指出的,可以使用ExecuteScalar
而不是ExecuteReader
来执行从一行只返回一列的查询。ExecuteScalar的性能更好,因为它没有构造一个OleDbDataReader对象来保持连接繁忙和打开直到关闭。它只返回请求的单个值,但您需要谨慎,因为如果查询没有找到任何与where子句匹配的用户,则返回值将为空
....
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.Red()。你可以在那一行有一个空读卡器。
让我们假设您的用户键入明文密码,然后您应该对其进行散列,并与数据库中的单向散列进行比较。
相反,代码的一般结构应该是:
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);
}
}