从OleDbCommand返回值

5
sqlQuery = "SELECT [ID] from [users] WHERE CallerName=@CallerName";

OleDbConnection conn = new OleDbConnection(connectionString);
conn.Open();
cmd = new OleDbCommand(sqlQuery, conn);
cmd.CommandText = sqlQuery;
cmd.Parameters.Add("@CallerName", OleDbType.VarChar).Value = labelProblemDate.Text.Trim();
cmd.Parameters["@CallerName"].Value = name;
cmd.ExecuteNonQuery();          
conn.Close();

我被告知这是使用参数从SELECT查询中读取数据的方法,但它没有起作用。我觉得我做错了什么。

我正在使用WinForms和Microsoft Access 2007。


你收到了哪些错误信息?同时,你似乎在 @CallerName 参数上有点混淆。变量 "name" 是什么?此外,ExecuteNonQuery 不会执行选择操作。 - Ste
1
你想要这个名字对应的所有ID还是只需要一个?如果是后者的话最好使用 SELECT TOP 1 ID FROM [users] WHERE CallerName=@CallerName。然后使用 ExecuteScalar(链接在内)只检索所选ID中的一个(如果有的话)。 - Tim Schmelter
4个回答

7

看起来你已经得到了答案,但是我想指出你示例代码中的一些问题:

sqlQuery = "SELECT [ID] from [users] WHERE CallerName=@CallerName";

OleDbConnection conn = new OleDbConnection(connectionString);
conn.Open();
cmd = new OleDbCommand(sqlQuery, conn);
cmd.CommandText = sqlQuery;
cmd.Parameters.Add("@CallerName", OleDbType.VarChar).Value = labelProblemDate.Text.Trim();
cmd.Parameters["@CallerName"].Value = name;
cmd.ExecuteNonQuery();
conn.Close();

首先,注意到您的SQL查询使用的是Microsoft SQL语法,而Microsoft Access更喜欢稍微不同的语法。不要用方括号包含您的列名,而是使用波浪线:

sqlQuery = "SELECT `ID` from `users` WHERE `CallerName`=@CallerName";

接下来,在您的SQL查询中,请注意Microsoft Access不接受命名参数。 您上面使用的@CallerName SQL文本将没有问题地执行,但是所有OleDb对象将看到以下内容:
sqlQuery = "SELECT `ID` from `users` WHERE `CallerName`=?";

如果您决定使用存储过程而不是文本SQL,请记得在添加参数并执行命令前,在OleDbCommand上调用Prepare()
如果您有多个参数,请确保按照SQL文本中调用它们的顺序将这些参数添加到OleDbCommand中。OleDb不关心您如何命名它们,但您可以使用它们来帮助自己;它不会在查询中使用。例如,@CallerName将不会尝试与SQL文本中的任何内容匹配。
接下来,我想看一下您对OleDbParameter项的使用。在下面的两行中,您正在向OleDbCommand添加一个(1)值为labelProblemDate.Text.Trim()的参数,然后在紧接着的下一行中,您正在重新分配相同参数的值给一个名为name的变量(我们不知道该变量是什么)。声明具有一个值的参数然后将其重新分配给其他值没有任何好处。
您可以使用以下修改后的片段并获得相同的结果(请记得添加大小字段,如下所示,并在数据库中指定):
cmd.Parameters.Add("@CallerName", OleDbType.VarChar, 255).Value = labelProblemDate.Text.Trim();
// cmd.Parameters["@CallerName"].Value = name;

同样地,您的 OleDbCommand 正在使用您的 sqlQuery 参数创建,因此指定命令的 CommandText 属性是不必要的:
cmd = new OleDbCommand(sqlQuery, conn);
//cmd.CommandText = sqlQuery;

最后,像其他人说的那样,如果您想查询您的数据,就必须读取数据,而不是调用ExecuteNonQuery()(注意它被称为非查询)。

总之,我在这里写出来:

sqlQuery = "SELECT `ID` from `users` WHERE `CallerName`=?";
int result = 0;
OleDbConnection conn = new OleDbConnection(connectionString);
try {
  conn.Open();
  var cmd = new OleDbCommand(sqlQuery, conn);
  //cmd.CommandText = sqlQuery; This command was specified by your initializer
  cmd.Parameters.Add("?", OleDbType.VarChar, 255).Value = labelProblemDate.Text.Trim();
  //cmd.Parameters["@CallerName"].Value = name; Possible bug here
  using (OleDbDataReader reader = cmd.ExecuteReader())
  {
    if(reader.HasRows)
    {
      reader.Read();
      result = reader.GetInt32(0);
    }
  }
} finally {
  conn.Close();
}
return result;

始终将 Close 放在 finally 块中,以防程序因任何原因抛出错误。这可以防止应用程序崩溃并保持文件打开状态。我发现,using 子句不一定在完成后关闭连接(就像它们应该做的那样)。
希望这可以帮助您。我目前正在刷新我对 OleDb 的了解,并想指出一些事情。

我认为使用语句应该可以关闭连接... 在什么情况下它们无法做到? - TulkinRB
这就是 using语句 应该做的事情。我不确定为什么Access没有这样做。只是猜测,我会说这是因为Access数据库通常是本地的并且在用户的个人电脑上,Access团队决定在程序运行时没有关闭他们的数据库的必要性。 - user153923
你是在谈论连接池吗?如果是的话,这实际上是一个好主意,因为你不需要为打开连接付出额外的开销,而且你可以将“关闭”的连接视为已经关闭(ASP将在服务器关闭后为您关闭它们)。我认为使用 finally-connection.close() 也是这样工作的。 - TulkinRB
我不确定Access是否使用连接池。只有一个数据库,每次只能打开一个连接。 - user153923

6

ExecuteNonQuery方法不返回数据,只返回受影响的行数。
如果需要获取数据,您应该使用OleDbDataReader类的ExecuteReader方法。

OleDbDataReader reader = cmd.ExecuteReader();           
if(reader.HasRows)
{
    reader.Read();
    var result = reader.GetInt32(0);
}

2
如果查询返回一个值,您可以使用 ExecuteScalar 来检索该值。 ExecuteNonQuery 不会从数据库中返回值;相反,它适用于 UPDATE 等语句,并返回受语句影响的行数。
通常情况下,SELECT 查询可能会返回多个行(以及多个列),因此要“从 SELECT 查询中读取数据”,需要使用 ExecuteReader 获取DbDataReader

1
读取数据并将其加载到 DataTable 中:
OleDataReader rdr = (OleDataReader) cmd.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(rdr);

读取比例值数据并将其加载到变量中:

int result = (int)cmd.ExecuteScalar(); //Assume scalar value to be return is int

希望能对您有所帮助


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接