【问题标题】:Is order of parameters for database Command object really important?数据库命令对象的参数顺序真的很重要吗?
【发布时间】:2011-11-02 04:47:59
【问题描述】:

我正在调试一个数据库操作代码,我发现虽然代码从未失败,但正确的 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 期望哪个顺序,并且在顺序发生更改的所有情况下,查询都不会在没有警告/错误的情况下完成其预期任务!!

【问题讨论】:

  • 你的查询模板是不是缺少一些语法来给参数槽命名?在没有名称的情况下,库可能会假设您希望按照它们出现的顺序填写它们。您是否希望数据库引擎随机选择出现在模板中 ? 附近的单词并假设这是您要为其使用的名称?
  • @Henning Makholm 哦,可能就是这样。让我看看是不是..
  • @Henning Makholm ,不,那不是问题。我摆脱了? 并包含了带有和不带有@ 的专有名称。顺序真的很重要。在这两种情况下,只有最后提到 WHERE 子句参数时,才会发生实际更新。可能与 OleDbCommand 类有关。
  • “可能与 OleDbCommand 类有关。” - 它与 OLEDB 本身有关。参数是严格定位的。在大多数(如果不是全部)情况下,我们可以为参数分配名称(而不是全部调用"?"),但这些名称被忽略

标签: c# database ms-access oledbcommand dbcommand


【解决方案1】:

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

假设您的 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 会导致奇怪的行为而没有错误消息,这可能会损坏您的数据库或导致向用户显示错误信息。

我还可以补充一点,当查询存储在带有指定参数的 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 文本,然后解析出参数名称和类型。

【讨论】:

  • +1 表示第一句话。谢谢。其余的答案是否回答了这里的具体问题?
  • 感谢 nawfal,是的,我认为确实如此,另外还提到了一些有关您可能遇到的奇怪和意外事情的警告,以及如何避免这些问题。
  • 嗯,我喜欢 Jet/Ace 引擎,它的工作还不错,但是男孩,Office 套件下 MS 提供的 GUI 太糟糕了!
  • 2003 年的 GUI 不错,但我同意 2007 年的情况很糟糕。从未真正看过 2010 年。
  • 我不同意,它只会变得更好,但它无法匹配那些附带的客户端,例如 MySQL。
【解决方案2】:

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

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

【讨论】:

  • 汉斯,如果是这样的话,我会觉得很沮丧。通过一些复杂的查询,我究竟应该如何知道 Access 的顺序。使用 sqlite 或 mysql 非常容易。如果你不知道.NET,你应该学习它。太棒了:)
  • 嗯。如果您能找到一种从 .NET 使用DAO 的方法(可能是互操作程序集?),您可能会更开心,因为通过DAO.QueryDef 执行的查询似乎确实如我所愿地尊重参数名称(IIRC)。至于ADO的参数顺序要求,对我来说并没有太大的负担……也许是因为我做了这么多年。 RE .NET,这听起来很诱人,我最终会到达那里......但不要屏住呼吸。 :-)
  • 我不明白 ADO DAO 的事情。我使用了带有 ADO .NET 连接器的 sqlite 和 mysql。他们不需要保留订单。只有 oledb 需要。那么这是否意味着它与 ADO 及其特定于 MS Access 的东西无关?
  • 参数顺序不是 DAO 加 Access 的问题,而是 ADO/OleDb 加 Access 的问题。所以我认为这是特定于 ADO/OleDb 和 Access 组合的东西,而不是特定于 Access 本身的东西。
  • 汉斯,现在我明白了。我正在寻找的正确答案。再次感谢您提供信息
【解决方案3】:

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

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

【讨论】:

  • 不,那没有用。我的意思是这段代码只能按照你提到的顺序工作,而不是我第一篇文章中的顺序(即使没有 ? 占位符)
  • 有趣 - 可能特定于 MS Access / OleDbCommand 组合(我用 SQL Server 尝试了我以前的解决方案,效果很好)。也许尝试更新的答案?
  • 我都试过了。它仅在最后给出 WHERE 参数时才有效。我的意思是必须维持秩序。是的,它与 MS Access 一起使用。 MySQL 也没有这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-27
  • 1970-01-01
相关资源
最近更新 更多