关于 ODP.NET 中 OracleCommand.BindByName 属性

下班前被同事叫过去,一个关于 C# 的问题,据她说。

经过近 90 分钟的鏖战,我终于确定不是 C# 的问题,更不是 Microsoft 的问题,而 Oracle 的问题,是 ODP.NET 的问题。

这是一个看起来比较怪的问题,在 PL/SQL 中能够查到数据的 SQL 语句,在 .Net 中就是没有数据,只因为使用了“参数化 SQL”。Oracle 又没有像 SQL Server 那样方便的事件探查器(SQL Server Profiler),所以浪费了我太多的时间,怀念 SQL Server 中……

首先,分析 OracleHelper 类是否正确的添加了参数,参数名、类型、值等是否正确;问题依旧。

其次,测试 SQL 语句是否正确,并在 PL/SQL Developer 中使用 bind variable 的方法确认参数绑定是否正确;问题依旧。

最后,建立新的 WinForm 应用程序,使用 System.Data.OracleClient 命名空间提供的类,重新写段测试代码;终于查询出正确的结果了。(一个小时没有了,人家项目组的人都走得差不多了)

再次打开同事的代码,我才注意到人家引用的 Assembly 是 Oracle.DataAccess,并没有使用 Microsoft 的 OracleClient,而是 Oracle 的 ODP.NET。此时,我基本上确定了问题的范围:找 ODP.NET 和 Microsoft OracleClient 的差异

又经过近 30 分钟的排查,我实在是无能为力了,代码找不出任何问题,总不能建议项目组换回 Microsoft OracleClient 吧!我抱着最后一点儿希望,翻了一遍 Oracle.DataAccess 中 OracleCommand 提供的 Property 和 Method。此时我看到了 BindByName 这个 Property。

将 BindByName 设置为 true,问题解决了!到这儿,我才恍然大悟,原来是参数的顺序不正确!!!

除了设置 BindByName 之外,只要按照 SQL 语句中参数出现的顺序,调整一下数据元素的位置,问题同样可以解决!!!难怪同事说,删除了一个条件后就会有数据。

我还是太大意了,不够细心。

好了,最后给大家三个链接,是为了这篇 Blog 刚刚搜索的,建议您也看看。

Comparing the Microsoft .NET Framework 1.1 Data Provider for Oracle and the Oracle Data Provider for .NET

By default, ODP.NET parameters for OracleCommand.CommandType = Text commands are bound by position. The OracleCommand class provides a BindByName property—set this property to true to bind parameters by name instead of by position. The Microsoft provider always binds parameters by name.

BindByName system level setting

Is there or will there ever be a system level parameter for OracleCommand.BindByName. It's very frustrating to have to set it everywhere, especially if you have common frameworks that use the generate IDbCommand/IDbConnection interfaces with a Connection factory.
We had to put an explicit type test into our Persistance framework just to see if it was an OracleCommand and set that property. That means EVERY call regardless of the target database has to go through that check

OracleCommand Class

BindByName

This property specifies the binding method in the collection.

Declaration

// C#
public bool BindByName {get; set;}

Property Value

Returns true if the parameters are bound by name; returns false if the parameters are bound by position.

Remarks

Default = false.

BindByName is ignored under the following conditions:

  • The value of the XmlCommandType property is Insert, Update, or Delete.

  • The value of the XmlCommandType property is Query, but there are no parameters set on the OracleCommand.

If the XmlCommandType property is OracleXmlCommandType.Query and any parameters are set on the OracleCommand, the BindByName property must be set to true. Otherwise, the following OracleCommand methods throw an InvalidOperationException.

  • ExecuteNonQuery

  • ExecuteXmlReader

  • ExecuteStream

  • ExecuteToStream

posted on 2007-07-16 22:16  gucs  阅读(2968)  评论(2编辑  收藏

导航