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

时间:2011-08-23 18:16:59

标签: c# database ms-access oledbcommand dbcommand

我正在调试数据库操作代码,我发现虽然代码从未失败过,但从未发生过正确的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等)需要维护的特定订单?

  4. 更新:我删除了?,并在包含和不包含@的情况下包含了专有名称。订单非常重要。在这两种情况下,只有在最后提到WHERE子句参数时才会发生实际更新。更糟糕的是,在复杂的查询中,很难知道自己哪个订单是Access期望的,并且在订单被更改的所有情况下,查询都没有执行其预期的任务而没有警告/错误!!

3 个答案:

答案 0 :(得分:5)

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

虽然我发现您的问题是关于c#和OleDbCommand,但我认为Dot.Net OleDbCommand可能与Access ADODB.Command的操作相同。不幸的是,我不知道Dot.Net ......但那是我的预感。 : - )

答案 1 :(得分: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);                         

答案 2 :(得分:2)

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

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

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中且指定了参数时,就像我上面的例子一样,参数的排序由参数-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的额外调用,它会检索SQL文本,然后解析参数名称和类型。