Oracle 的 C# 参数化查询 - 严重&危险的错误!
这绝对是一个嚎叫。我不敢相信自己的眼睛,而且我不敢相信,如果这是 C# 中的一个真正的错误,那么在我之前没有人会发现这一点,所以我将其发布给开发人员社区的其他成员,让他们告诉我我做错了什么。我确信这个问题会让我说“DOH!”然后用手掌用力拍打我的头 - 但无论如何,这里是......
为了测试,我创建了一个表 Test_1
,脚本如下:
CREATE TABLE TEST_1 (
COLUMN1 NUMBER(12) NOT NULL,
COLUMN2 VARCHAR2(20),
COLUMN3 NUMBER(12))
TABLESPACE USERS
STORAGE (
INITIAL 64K
MAXEXTENTS UNLIMITED
)
LOGGING;
现在我执行以下代码:
var conn = new OracleConnection("connectionblahblah");
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText =
"insert into Test_1(Column1, Column2, Column3) " +
"values(:Column1, :Column2, :Column3)";
var p = cmd.Parameters;
p.Add("Column1", 1);
p.Add("Column3", null);
p.Add("Column2", "record 1");
cmd.ExecuteNonQuery();
哇!我收到 ORA-01722 错误 - “无效数字”!但有什么问题吗? Column1
是数字,并且值为 1,所以没问题; Column2
是一个字符串,Column3
是一个可为空的列,因此不会造成任何麻烦...
现在坐下来讨论这个...这里的问题是Column3
和 Column2
按照它们添加到 OracleParameterCollection
的顺序进行调换。交换它们,然后!有用!
当然,这引导我进行下一个明显的实验...让我们更改添加参数的代码块,如下所示:
p.Add("Foo", 1);
p.Add("Bar", "record 1");
p.Add("hahahahahahaha", null);
您认为这会起作用吗?好吧,你猜怎么着——它能!
我坐在这里完全惊呆了。我无法相信我所看到的,而且我同样无法相信在我之前没有人发现这种行为(除非我不知道如何正确使用谷歌)。
这不仅是一种烦恼,而且是非常危险的。如果我调换相同数据类型的两列会发生什么?我什至不会得到一个错误——我只会将错误的数据插入到错误的列中,并且一无所知。
有没有人有任何解决方法的想法 - 除了小心不要以错误的顺序添加参数之外?
This is an absolute howler. I cannot believe my own eyes, and I cannot believe nobody before me would have discovered this if it was a genuine bug in C#, so I'm putting it out for the rest of the developer community to tell me what I am doing wrong. I'm sure this question is going to involve me saying "DOH!" and smacking my head very hard with the palm of my hand - but here goes, anyway...
For the sake of testing, I have created a table Test_1
, with script as follows:
CREATE TABLE TEST_1 (
COLUMN1 NUMBER(12) NOT NULL,
COLUMN2 VARCHAR2(20),
COLUMN3 NUMBER(12))
TABLESPACE USERS
STORAGE (
INITIAL 64K
MAXEXTENTS UNLIMITED
)
LOGGING;
Now I execute the following code:
var conn = new OracleConnection("connectionblahblah");
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText =
"insert into Test_1(Column1, Column2, Column3) " +
"values(:Column1, :Column2, :Column3)";
var p = cmd.Parameters;
p.Add("Column1", 1);
p.Add("Column3", null);
p.Add("Column2", "record 1");
cmd.ExecuteNonQuery();
Whoa! I get an ORA-01722 error - "invalid number"! What's wrong, though? Column1
is numeric, and has a value of 1, so that's fine; Column2
is a string, and Column3
is a nullable column, so that shouldn't cause any trouble...
Now sit down for this one... the problem here is that Column3
and Column2
are transposed in the order in which they are added to the OracleParameterCollection
. Switch them around, and presto! It works!
This, of course, leads me to the next obvious experiment... let's change that block of code for adding parameters like so:
p.Add("Foo", 1);
p.Add("Bar", "record 1");
p.Add("hahahahahahaha", null);
You think that'll work? Well guess what - it does!
I am sitting here absolutely stunned. I cannot believe what I am seeing, and I likewise cannot believe that nobody before me has discovered this behavior (unless I don't know how to use Google properly).
This is not just an annoyance - it is seriously dangerous. What would have happened if I'd transposed two columns of the same data type? I wouldn't have even got an error - I would have simply inserted the wrong data into the wrong columns, and been none the wiser.
Does anyone have any ideas for a workaround - other than just being careful not to add parameters in the wrong order?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这不是一个错误,但在 Oracle ODP.Net 文档中明确提到。在 OracleCommand 类中,参数默认按位置绑定。如果您想按名称绑定,请显式设置属性
cmd.BindByName = true;
。参考 Oracle 文档。
http://download.oracle.com/docs /cd/E11882_01/win.112/e12249/OracleCommandClass.htm#i997666
This is not a bug but explicitly mentioned in Oracle ODP.Net documentation. In a OracleCommand class the parameters are bound by position as default. If you want to bind by name then set the property
cmd.BindByName = true;
explicitly.Reference to Oracle documentation.
http://download.oracle.com/docs/cd/E11882_01/win.112/e12249/OracleCommandClass.htm#i997666
您是否在column2之前添加了column3,这是一个拼写错误吗?
因为冒号语法表示绑定变量,所以名称对于 PLSQL 中的 BIND 变量来说并不重要,因此它们按照提交的顺序填充。这意味着您将尝试将column2值设置为“记录1”,这将解释无效数字错误...
您当前有:
...看看此更改是否解决了您的问题:
让命名参数起作用?
我必须请具有更多 C# 经验的人来解释如何使命名参数正常工作。但我很高兴我们确认冒号似乎被解释为 Oracle BIND 变量。
Is that a typo that you have column3 being added before column2?
Because the colon syntax signifies a bind variable--name doesn't matter to BIND variables in PLSQL, they're populated in order of submission. Which would mean you'd be attempting to set column2 value as "record 1", which would explain the invalid number error...
You currently have:
...see if this alteration fixes your issue:
Getting Named Parameters to Work?
I have to defer to someone with more C# experience to explain how to get named parameters working. But I'm glad we confirmed that the colon appears to be interpreting as an Oracle BIND variable.
//注意我已将 : 添加到参数名称中以供 Oracle 数据客户端识别
//NOTE i have added : to the parameter names to be recognised by oracle data client