4

我正在调试数据库操作代码,我发现正确的 UPDATE 从未发生,尽管代码从未失败过。这是代码:

        condb.Open();
        OleDbCommand dbcom = new OleDbCommand("UPDATE Word SET word=?,sentence=?,mp3=? WHERE id=? AND exercise_id=?", condb);
        dbcom.Parameters.AddWithValue("id", wd.ID);
        dbcom.Parameters.AddWithValue("exercise_id", wd.ExID);
        dbcom.Parameters.AddWithValue("word", wd.Name);
        dbcom.Parameters.AddWithValue("sentence", wd.Sentence);
        dbcom.Parameters.AddWithValue("mp3", wd.Mp3);

但经过一些调整后,这奏效了:

        condb.Open();
        OleDbCommand dbcom = new OleDbCommand("UPDATE Word SET word=?,sentence=?,mp3=? WHERE id=? AND exercise_id=?", condb);
        dbcom.Parameters.AddWithValue("word", wd.Name);
        dbcom.Parameters.AddWithValue("sentence", wd.Sentence);
        dbcom.Parameters.AddWithValue("mp3", wd.Mp3);                         
        dbcom.Parameters.AddWithValue("id", wd.ID);
        dbcom.Parameters.AddWithValue("exercise_id", wd.ExID);
  1. 为什么在 OleDb 连接的情况下必须将 WHERE 子句中的参数放在最后一个如此重要?之前使用过 MySQL,我可以(并且通常会)首先编写 WHERE 子句的参数,因为这对我来说更合乎逻辑。

  2. 一般查询数据库时参数顺序是否重要?一些性能问题还是什么?

  3. 对于 DB2、Sqlite 等其他数据库,是否需要维护特定的顺序?

更新:我删除?并包含了带有和不带有@. 顺序真的很重要。在这两种情况下,只有最后提到 WHERE 子句参数时,才会发生实际更新。更糟糕的是,在复杂的查询中,我们很难知道 Access 期望哪个顺序,并且在所有顺序发生更改的情况下,查询都不会在没有警告/错误的情况下完成其预期的任务!

4

3 回答 3

5

在 Access 中,ADODB.Command对象会忽略参数名称。事实上,我可以使用假名(甚至在 SQL 语句中不存在)来引用参数,而 ADO 不在乎。它似乎只关心您提供参数值的顺序与这些参数出现在 SQL 语句中的顺序完全相同。?顺便说一句,如果我使用占位符而不是命名参数构建 SQL 语句,也会发生这种情况。

虽然我意识到您的问题是关于 c# 和OleDbCommand,但在我看来,Dot.Net 的OleDbCommand运行方式可能与 Access 相同ADODB.Command。不幸的是,我不知道 Dot.Net ......但这是我的预感。:-)

于 2012-07-11T01:48:33.987 回答
2

顺序很重要,因为使用 ? 命令字符串中的占位符。

如果要按任意顺序列出参数,最好使用命名参数,例如@word、@sentence 等。

condb.Open();
OleDbCommand dbcom = new OleDbCommand("UPDATE Word SET word=@word,sentence=@sentence,mp3=@mp3 WHERE id=@id AND exercise_id=@exercise_id", condb);
dbcom.Parameters.AddWithValue("@id", wd.ID);
dbcom.Parameters.AddWithValue("@exercise_id", wd.ExID);
dbcom.Parameters.AddWithValue("@word", wd.Name);
dbcom.Parameters.AddWithValue("@sentence", wd.Sentence);
dbcom.Parameters.AddWithValue("@mp3", wd.Mp3);                         
于 2011-08-23T18:24:30.827 回答
2

我一直在使用 OleDbCommand 及其针对 Access DB 的参数集合进行一些测试。参数的顺序当然是必要的,因为这是OLE DB .NET 提供程序的限制。但是使用问号作为占位符时可能会遇到一个问题。

假设您的 Access DB 中有一个查询(“存储过程”),看起来像这样,这里非常简化:

parameters
  prmFirstNumber Long,
  prmSecondNumber Long;
select
  fullName
from
  tblPersons
where 
  numberOfCars < prmFirstNumber And
  numberOfPets < prmSecondNumber And
  numberOfBooks beteween prmFirstNumber And prmSecondNumber

在这里,您会看到简单地更改为问号会破坏查询。

不过,我发现,作为解决方案,您实际上可以使用参数名称。所以你可以让上面的查询保持原样。您只需在运行查询时使用相同的顺序。就像在这种情况下,您首先添加参数 prmFirstNumber,然后添加 prmSecondNumber,然后运行查询。

当重用参数时,即多次执行查询并每次为参数设置新值时,必须在定义参数后立即调用命令对象的prepare方法。那里也有一些细节需要完成,请查看“准备”文档。不调用 prepare 会导致奇怪的行为而没有错误消息,这可能会损坏您的数据库或导致向用户显示错误信息。

我还可以补充一点,当查询存储在带有指定参数的 Access DB 中时,就像上面的示例一样,参数的顺序由参数部分明确定义。

我还创建了一个例程“retrieveDeclaredJetParametersInOrder”,它以正确的顺序使用这些命名参数自动填充 OleDbCommand 对象。所以我的代码看起来像这样:

Dim cmd As New OleDbCommand("qryInAccessDB", Conn)
cmd.CommandType = CommandType.StoredProcedure
Conn.Open()
retrieveDeclaredJetParametersInOrder(cmd)
cmd.Parameters("prmOneOfTheParametersPerhapsTheLastOneDeclared").Value = 1
cmd.Parameters("prmAnotherone").Value = 20
cmd.Parameters("prmYetAnotherPerhapsTheFirstOneDeclared").Value = 300
cmd.ExecuteNonQuery()
Conn.Close()

因此,如您所见,我可以像命名参数一样处理它,而不必为它们的顺序而烦恼。

retrieveDeclaredJetParametersInOrder 当然会增加额外的执行时间,因为它涉及对 DB 的额外调用,它在其中检索 SQL 文本,然后解析出参数名称和类型。

于 2012-11-24T17:02:38.720 回答