Oracle UDF 问题 - 对象传递到存储过程但插入 NVARCHAR2,没有插入 DECIMAL
我们有一个表:
CREATE TABLE ESIPARIS.T_ORDER_LINE
(
NO NUMBER(18),
ORDER_NO NUMBER(18),
ITEM_NO NVARCHAR2(15),
AMOUNT NUMBER(18,3),
INSERT_DATE DATE,
INSERT_USER NVARCHAR2(20),
UPDATE_DATE DATE,
UPDATE_USER NVARCHAR2(20),
FLEXFIELD_1 NVARCHAR2(100),
FLEXFIELD_2 NVARCHAR2(100),
FLEXFIELD_3 NVARCHAR2(100),
FLEXFIELD_4 NVARCHAR2(100)
)
TABLESPACE DEVEL
PCTUSED 0
PCTFREE 10
INITRANS 1
MAXTRANS 255
STORAGE (
INITIAL 64K
NEXT 1M
MINEXTENTS 1
MAXEXTENTS UNLIMITED
PCTINCREASE 0
BUFFER_POOL DEFAULT
)
NOLOGGING
NOCOMPRESS
NOCACHE
NOPARALLEL
MONITORING;
对象:
DROP TYPE ESIPARIS.ORDER_LINE_ROW;
CREATE OR REPLACE TYPE ESIPARIS.ORDER_LINE_ROW AS OBJECT
(
NO NUMBER(18),
ORDER_NO NUMBER(18),
ITEM_NO NVARCHAR2(15),
AMOUNT NUMBER(18,3),
INSERT_DATE DATE,
INSERT_USER NVARCHAR2(20),
UPDATE_DATE DATE,
UPDATE_USER NVARCHAR2(20),
FLEXFIELD_1 NVARCHAR2(100),
FLEXFIELD_2 NVARCHAR2(100),
FLEXFIELD_3 NVARCHAR2(100),
FLEXFIELD_4 NVARCHAR2(100)
)
/
CREATE OR REPLACE TYPE ESIPARIS.ORDER_LINE_TABLE as table of ESIPARIS.ORDER_LINE_ROW;
/
以及一个存储过程,用于处理 .NET 应用程序发送的对象以插入行:
CREATE OR REPLACE PROCEDURE ESIPARIS.pr_getorder_line (
deneme IN order_line_table
)
IS
err_code NVARCHAR2 (500) := '';
err_msg NVARCHAR2 (500) := '';
BEGIN
FOR i IN 1 .. deneme.COUNT
LOOP
INSERT INTO t_order_line
(NO, order_no, item_no,
amount, insert_date,
insert_user, update_date,
update_user, flexfield_1,
flexfield_2, flexfield_3,
flexfield_4
)
VALUES (deneme (i).NO, deneme (i).order_no, nvl(deneme (i).item_no,'null geldi'),
nvl(deneme (i).amount,5363377869), deneme (i).insert_date,
deneme (i).insert_user, deneme (i).update_date,
deneme (i).update_user, deneme (i).flexfield_1,
deneme (i).flexfield_2, deneme (i).flexfield_3,
deneme (i).flexfield_4
);
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
err_code := SQLCODE;
err_msg := SUBSTR (SQLERRM, 1, 200);
INSERT INTO esiparis.t_error_log
(event_date, event_object, MESSAGE
)
VALUES (SYSDATE, err_code, err_msg
);
END;
/
我们创建了 UDT .NET 4.0 中使用 Visual Studio 2010 和 ODP.NET 插件。我们正处于插入由 .NET 应用程序发送的 NVARCHAR2 数据类型的值的时刻。无法插入 NUMBER 或 DATE 数据类型的数据。有什么想法吗?
We have a table as:
CREATE TABLE ESIPARIS.T_ORDER_LINE
(
NO NUMBER(18),
ORDER_NO NUMBER(18),
ITEM_NO NVARCHAR2(15),
AMOUNT NUMBER(18,3),
INSERT_DATE DATE,
INSERT_USER NVARCHAR2(20),
UPDATE_DATE DATE,
UPDATE_USER NVARCHAR2(20),
FLEXFIELD_1 NVARCHAR2(100),
FLEXFIELD_2 NVARCHAR2(100),
FLEXFIELD_3 NVARCHAR2(100),
FLEXFIELD_4 NVARCHAR2(100)
)
TABLESPACE DEVEL
PCTUSED 0
PCTFREE 10
INITRANS 1
MAXTRANS 255
STORAGE (
INITIAL 64K
NEXT 1M
MINEXTENTS 1
MAXEXTENTS UNLIMITED
PCTINCREASE 0
BUFFER_POOL DEFAULT
)
NOLOGGING
NOCOMPRESS
NOCACHE
NOPARALLEL
MONITORING;
And objects as:
DROP TYPE ESIPARIS.ORDER_LINE_ROW;
CREATE OR REPLACE TYPE ESIPARIS.ORDER_LINE_ROW AS OBJECT
(
NO NUMBER(18),
ORDER_NO NUMBER(18),
ITEM_NO NVARCHAR2(15),
AMOUNT NUMBER(18,3),
INSERT_DATE DATE,
INSERT_USER NVARCHAR2(20),
UPDATE_DATE DATE,
UPDATE_USER NVARCHAR2(20),
FLEXFIELD_1 NVARCHAR2(100),
FLEXFIELD_2 NVARCHAR2(100),
FLEXFIELD_3 NVARCHAR2(100),
FLEXFIELD_4 NVARCHAR2(100)
)
/
CREATE OR REPLACE TYPE ESIPARIS.ORDER_LINE_TABLE as table of ESIPARIS.ORDER_LINE_ROW;
/
And a stored procedure to handle objects sent by a .NET application to insert rows:
CREATE OR REPLACE PROCEDURE ESIPARIS.pr_getorder_line (
deneme IN order_line_table
)
IS
err_code NVARCHAR2 (500) := '';
err_msg NVARCHAR2 (500) := '';
BEGIN
FOR i IN 1 .. deneme.COUNT
LOOP
INSERT INTO t_order_line
(NO, order_no, item_no,
amount, insert_date,
insert_user, update_date,
update_user, flexfield_1,
flexfield_2, flexfield_3,
flexfield_4
)
VALUES (deneme (i).NO, deneme (i).order_no, nvl(deneme (i).item_no,'null geldi'),
nvl(deneme (i).amount,5363377869), deneme (i).insert_date,
deneme (i).insert_user, deneme (i).update_date,
deneme (i).update_user, deneme (i).flexfield_1,
deneme (i).flexfield_2, deneme (i).flexfield_3,
deneme (i).flexfield_4
);
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
err_code := SQLCODE;
err_msg := SUBSTR (SQLERRM, 1, 200);
INSERT INTO esiparis.t_error_log
(event_date, event_object, MESSAGE
)
VALUES (SYSDATE, err_code, err_msg
);
END;
/
We have created UDT classes in .NET 4.0 using the Visual Studio 2010 and the ODP.NET plugin. We are at a point that values sent by a .NET application that are in NVARCHAR2 data type are inserted. Data in NUMBER or DATE data types cannot be inserted. Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的问题可能是由于调用 C# 代码中的本机 .NET 类型(int、double、DateTime 等)到用于在数据库中存储值的 Oracle 类型(NUMBER、DATE)的类型转换所致。确保 UDT 类使用 Oracle 类型,而不是 .NET 类型。
另外,如果您所做的只是迭代集合以插入记录,那么您应该考虑使用 Oracle 的批量绑定功能,因为它会更加高效。请参阅 http://dotnetslackers.com/articles/ado_net/BulkOperationsUsingOracleDataProviderForNETODPNET.aspx 了解更多信息例子。
编辑:
根据您的评论:“我们正在寻找直接的 SP 示例。这对于使用绑定变量很有好处。”
无论哪种方式,您都需要将类型从 .NET 正确转换为 Oracle。听起来您正在执行本文档中的操作:
http://download.oracle.com/docs/html/E15167_01/featUDTs .htm#CJAGFHBA
编辑2:
根据您自己发布的答案中的代码,看起来有一个(稍微)更好的方法来解决这个问题。
您注释掉了如下几行:
m_AMOUNTIsNull
(或使用该字段的属性AMOUNTIsNull
)的目的是允许代码区分实际的m_AMOUNT< /code> 设置的值和由于使用默认 .NET 值(0 表示小数)而设置的值。
这就是为什么在使用
m_AMOUNT
值填充 UDT 之前检查该值的原因:从数据库获取 UDT 时,会根据数据库字段是否为空来设置
AMOUNTIsNull
:但是当您使用 .NET 对象并设置
AMOUNT
属性时,AMOUNTIsNull
不会改变:如果您更改它,则它已正确设置(并撤消你已经做了注释掉的修复),你会更好,因为你既可以存储一个值,也可以代表一个空值:
Your problem is probably due to type conversion from native .NET types (int, double, DateTime, etc.) in your calling C# code to the Oracle types (NUMBER, DATE) used to store the values in the database. Ensure the UDT classes are using Oracle types, not .NET types.
Also, if all you're doing is iterating over your collection to insert records, you should consider using Oracle's bulk binding capabilities as it'll be much more efficient. See http://dotnetslackers.com/articles/ado_net/BulkOperationsUsingOracleDataProviderForNETODPNET.aspx for a good example.
EDIT:
Per your commment: "We were looking for a direct SP example. This was good for using bind variables."
Either way, you need to be properly converting the types from .NET to Oracle. It sounds like you're doing exactly what's in this document:
http://download.oracle.com/docs/html/E15167_01/featUDTs.htm#CJAGFHBA
EDIT2:
Based on the code in the answer you posted yourself, it looks like there's a (slightly) better way to fix that.
You commented out some lines like this:
The purpose of
m_AMOUNTIsNull
(or the propertyAMOUNTIsNull
which uses that field) is to allow the code to differentiate an actualm_AMOUNT
value that's set and one that's set because the default .NET value (0 for a decimal) is used.That's why the value is checked before the UDT is populated with the
m_AMOUNT
value:When the UDT is fetched from the database,
AMOUNTIsNull
is set based on whether the database field is null:But when you're using your .NET object and setting the
AMOUNT
property,AMOUNTIsNull
doesn't get altered:If you change it so it is properly set (and undo the commented-out fix you've already made), you'll be better off since you're able to both store a value AND represent a null value as well:
检查 Oracle ODP.NET Visual Studio 插件自动生成的类后,
我们的.NET 开发人员发现,在注释掉自动生成的代码中的一些行(从
“//[07.12.2010]ISMAILH : ISNULLS ARE COMMENTED OUT FOR PROPER WORKING!”之后开始的 4 行)后,它可以正常工作。
之后一切正常,但我想知道其更深层次的原因。为什么插件首先生成这些行? :
After checking out the auto generated classes by the Oracle ODP.NET Visual Studio plugin,
our .NET developer has found out that it worked normally after commenting out some lines in the auto generated code, 4 lines starting after the line
"//[07.12.2010]ISMAILH : ISNULLS ARE COMMENTED OUT FOR PROPER WORKING!".
After that everything worked properly, but I wonder about the deeper reason for that. Why did the plugin generate these lines at the first place? :