数据库命令对象的参数顺序真的很重要吗?

本文关键字:真的 顺序 命令 对象 参数 数据库 | 更新日期: 2023-09-27 18:06:22

我正在调试一个数据库操作代码,我发现正确的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期望的顺序是什么,而且在所有改变顺序的情况下,查询都不会在没有警告/错误的情况下完成预期的任务!!

数据库命令对象的参数顺序真的很重要吗?

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

虽然我意识到你的问题是关于c#和OleDbCommand,它看起来像Dot。Net的OleDbCommand可能与Access的ADODB.Command运行相同。不幸的是,我不认识Dot。网但这只是我的直觉。: -)

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

如果您想以任意顺序列出参数,最好使用命名参数,如@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);                         

我一直在做一些使用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中并指定参数时,就像我上面的例子一样,参数的顺序是由parameters-section明确定义的。

我还编写了一个例程,"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的额外调用,在DB中检索sql文本,然后解析出参数名称和类型。