problema Oracle UDF - oggetto passa alla stored procedure, ma fa inserto NVARCHAR2, nessun inserto, per decimali
-
09-10-2019 - |
Domanda
Abbiamo una tabella come:
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;
e oggetti come:
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;
/
E una stored procedure per gestire gli oggetti inviati da un'applicazione .NET per Inserisci righe:
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;
/
Abbiamo creato classi UDT in .NET 4.0 utilizzando il Visual Studio 2010 e il ODP.NET plugin. Siamo in un punto che valori inviati da un'applicazione NET che sono NVARCHAR2 tipo di dati inseriti. I dati in tipi di dati numero o una data non può essere inserito. Qualche idea?
Soluzione
Il vostro problema è probabilmente dovuto al tipo di conversione da tipi nativi NET (int, double, DateTime, ecc) nel chiamare codice C # per i tipi di Oracle (numero, data) utilizzati per memorizzare i valori nel database. Assicurarsi che l'UDT classi utilizzano tipi di Oracle, non tipi .NET.
Inoltre, se tutto quello che stai facendo è iterare sulla vostra collezione per inserire i record, si consiglia di utilizzare le capacità di legame di massa di Oracle come sarà molto più efficiente. Vedere http://dotnetslackers.com/articles/ado_net/BulkOperationsUsingOracleDataProviderForNETODPNET.aspx per una buona esempio.
EDIT: Per la tua commment: "Eravamo alla ricerca di un esempio diretto SP Questo è stato buono per l'utilizzo di variabili di bind.".
In entrambi i casi, è necessario essere convertire adeguatamente i tipi di .NET per Oracle. Suona come si sta facendo esattamente cosa c'è in questo documento: http://download.oracle.com/docs/html/E15167_01/featUDTs htm # CJAGFHBA
EDIT2: In base al codice nella risposta che hai postato te stesso, sembra che ci sia una (leggermente) il modo migliore per sistemare le cose.
ha commentato alcune linee in questo modo:
//[07.12.2010]ISMAILH : ISNULLS ARE COMMENTED OUT FOR PROPER WORKING!
// TODO : Add code to initialise the object
//this.m_AMOUNTIsNull = true;
Lo scopo di m_AMOUNTIsNull
(o AMOUNTIsNull
proprietà che utilizza tale campo) è quello di consentire il codice per differenziare un valore m_AMOUNT
effettivo che è impostato e uno che è impostato perché viene utilizzato il valore predefinito NET (0 per un decimale).
Ecco perché il valore viene controllato prima della UDT viene popolato con il valore m_AMOUNT
:
if ((AMOUNTIsNull == false)) {
Oracle.DataAccess.Types.OracleUdt.SetValue(con, pUdt, "AMOUNT", this.AMOUNT);
Quando l'UDT viene recuperata dal database, AMOUNTIsNull
è impostato a seconda che il campo del database è nullo:
this.AMOUNTIsNull = Oracle.DataAccess.Types.OracleUdt.IsDBNull(con, pUdt, "AMOUNT");
if ((AMOUNTIsNull == false)) {
this.AMOUNT = ((decimal)(Oracle.DataAccess.Types.OracleUdt.GetValue(con, pUdt, "AMOUNT")));
}
Ma quando si sta utilizzando il vostro oggetto .NET e impostando la proprietà AMOUNT
, AMOUNTIsNull
non ottiene alterato:
[OracleObjectMappingAttribute("AMOUNT")]
public decimal AMOUNT {
get {
return this.m_AMOUNT;
}
set {
this.m_AMOUNT = value;
}
}
Se si modifica in modo che sia correttamente impostato (e annullare la correzione commentato-out hai già fatto), si sarà meglio visto che sei in grado sia di memorizzare un valore e rappresentano un valore nullo pure :
[OracleObjectMappingAttribute("AMOUNT")]
public decimal AMOUNT {
get {
return this.m_AMOUNT;
}
set {
this.AMOUNTIsNull = false;
this.m_AMOUNT = value;
}
}
Altri suggerimenti
Dopo aver controllato le classi di auto generato dalla Oracle ODP.NET Visual Studio plug-in, il nostro sviluppatore .NET ha scoperto che ha funzionato normalmente dopo commentando alcune righe nel codice generato automaticamente, 4 linee di partenza dopo la riga
"// [07.12.2010] ISMAILH:! ISNULLS sono commentate PER LA LAVORAZIONE CORRETTA".
Dopo di che tutto ha funzionato correttamente, ma mi chiedo circa la ragione più profonda per questo. Perché il plugin genera queste righe al primo posto? :
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.1
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ESiparis {
using System;
using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;
using System.Xml.Serialization;
using System.Xml.Schema;
public class ORDER_LINE_ROW : INullable, IOracleCustomType, IXmlSerializable,IDisposable {
private bool m_IsNull;
private decimal m_AMOUNT;
private bool m_AMOUNTIsNull;
private System.DateTime m_UPDATE_DATE;
private bool m_UPDATE_DATEIsNull;
private string m_FLEXFIELD_1;
private System.DateTime m_INSERT_DATE;
private bool m_INSERT_DATEIsNull;
private string m_FLEXFIELD_3;
private string m_UPDATE_USER;
private string m_FLEXFIELD_2;
private decimal m_ORDER_NO;
private bool m_ORDER_NOIsNull;
private string m_FLEXFIELD_4;
private string m_INSERT_USER;
private decimal m_NO;
private bool m_NOIsNull;
private string m_ITEM_NO;
public ORDER_LINE_ROW() {
//[07.12.2010]ISMAILH : ISNULLS ARE COMMENTED OUT FOR PROPER WORKING!
// TODO : Add code to initialise the object
//this.m_AMOUNTIsNull = true;
//this.m_UPDATE_DATEIsNull = true;
//this.m_INSERT_DATEIsNull = true;
//this.m_ORDER_NOIsNull = true;
Dispose(false);
this.m_NOIsNull = true;
}
public ORDER_LINE_ROW(string str) {
// TODO : Add code to initialise the object based on the given string
Dispose(false);
}
public virtual bool IsNull {
get {
return this.m_IsNull;
}
}
public static ORDER_LINE_ROW Null {
get {
ORDER_LINE_ROW obj = new ORDER_LINE_ROW();
obj.m_IsNull = true;
return obj;
}
}
[OracleObjectMappingAttribute("AMOUNT")]
public decimal AMOUNT {
get {
return this.m_AMOUNT;
}
set {
this.m_AMOUNT = value;
}
}
public bool AMOUNTIsNull {
get {
return this.m_AMOUNTIsNull;
}
set {
this.m_AMOUNTIsNull = value;
}
}
[OracleObjectMappingAttribute("UPDATE_DATE")]
public System.DateTime UPDATE_DATE {
get {
return this.m_UPDATE_DATE;
}
set {
this.m_UPDATE_DATE = value;
}
}
public bool UPDATE_DATEIsNull {
get {
return this.m_UPDATE_DATEIsNull;
}
set {
this.m_UPDATE_DATEIsNull = value;
}
}
[OracleObjectMappingAttribute("FLEXFIELD_1")]
public string FLEXFIELD_1 {
get {
return this.m_FLEXFIELD_1;
}
set {
this.m_FLEXFIELD_1 = value;
}
}
[OracleObjectMappingAttribute("INSERT_DATE")]
public System.DateTime INSERT_DATE {
get {
return this.m_INSERT_DATE;
}
set {
this.m_INSERT_DATE = value;
}
}
public bool INSERT_DATEIsNull {
get {
return this.m_INSERT_DATEIsNull;
}
set {
this.m_INSERT_DATEIsNull = value;
}
}
[OracleObjectMappingAttribute("FLEXFIELD_3")]
public string FLEXFIELD_3 {
get {
return this.m_FLEXFIELD_3;
}
set {
this.m_FLEXFIELD_3 = value;
}
}
[OracleObjectMappingAttribute("UPDATE_USER")]
public string UPDATE_USER {
get {
return this.m_UPDATE_USER;
}
set {
this.m_UPDATE_USER = value;
}
}
[OracleObjectMappingAttribute("FLEXFIELD_2")]
public string FLEXFIELD_2 {
get {
return this.m_FLEXFIELD_2;
}
set {
this.m_FLEXFIELD_2 = value;
}
}
[OracleObjectMappingAttribute("ORDER_NO")]
public decimal ORDER_NO {
get {
return this.m_ORDER_NO;
}
set {
this.m_ORDER_NO = value;
}
}
public bool ORDER_NOIsNull {
get {
return this.m_ORDER_NOIsNull;
}
set {
this.m_ORDER_NOIsNull = value;
}
}
[OracleObjectMappingAttribute("FLEXFIELD_4")]
public string FLEXFIELD_4 {
get {
return this.m_FLEXFIELD_4;
}
set {
this.m_FLEXFIELD_4 = value;
}
}
[OracleObjectMappingAttribute("INSERT_USER")]
public string INSERT_USER {
get {
return this.m_INSERT_USER;
}
set {
this.m_INSERT_USER = value;
}
}
[OracleObjectMappingAttribute("NO")]
public decimal NO {
get {
return this.m_NO;
}
set {
this.m_NO = value;
}
}
public bool NOIsNull {
get {
return this.m_NOIsNull;
}
set {
this.m_NOIsNull = value;
}
}
[OracleObjectMappingAttribute("ITEM_NO")]
public string ITEM_NO {
get {
return this.m_ITEM_NO;
}
set {
this.m_ITEM_NO = value;
}
}
public virtual void FromCustomObject(Oracle.DataAccess.Client.OracleConnection con, System.IntPtr pUdt) {
if ((AMOUNTIsNull == false)) {
Oracle.DataAccess.Types.OracleUdt.SetValue(con, pUdt, "AMOUNT", this.AMOUNT);
}
if ((UPDATE_DATEIsNull == false)) {
Oracle.DataAccess.Types.OracleUdt.SetValue(con, pUdt, "UPDATE_DATE", this.UPDATE_DATE);
}
Oracle.DataAccess.Types.OracleUdt.SetValue(con, pUdt, "FLEXFIELD_1", this.FLEXFIELD_1);
if ((INSERT_DATEIsNull == false)) {
Oracle.DataAccess.Types.OracleUdt.SetValue(con, pUdt, "INSERT_DATE", this.INSERT_DATE);
}
Oracle.DataAccess.Types.OracleUdt.SetValue(con, pUdt, "FLEXFIELD_3", this.FLEXFIELD_3);
Oracle.DataAccess.Types.OracleUdt.SetValue(con, pUdt, "UPDATE_USER", this.UPDATE_USER);
Oracle.DataAccess.Types.OracleUdt.SetValue(con, pUdt, "FLEXFIELD_2", this.FLEXFIELD_2);
if ((ORDER_NOIsNull == false)) {
Oracle.DataAccess.Types.OracleUdt.SetValue(con, pUdt, "ORDER_NO", this.ORDER_NO);
}
Oracle.DataAccess.Types.OracleUdt.SetValue(con, pUdt, "FLEXFIELD_4", this.FLEXFIELD_4);
Oracle.DataAccess.Types.OracleUdt.SetValue(con, pUdt, "INSERT_USER", this.INSERT_USER);
if ((NOIsNull == false)) {
Oracle.DataAccess.Types.OracleUdt.SetValue(con, pUdt, "NO", this.NO);
}
Oracle.DataAccess.Types.OracleUdt.SetValue(con, pUdt, "ITEM_NO", this.ITEM_NO);
}
public virtual void ToCustomObject(Oracle.DataAccess.Client.OracleConnection con, System.IntPtr pUdt) {
this.AMOUNTIsNull = Oracle.DataAccess.Types.OracleUdt.IsDBNull(con, pUdt, "AMOUNT");
if ((AMOUNTIsNull == false)) {
this.AMOUNT = ((decimal)(Oracle.DataAccess.Types.OracleUdt.GetValue(con, pUdt, "AMOUNT")));
}
this.UPDATE_DATEIsNull = Oracle.DataAccess.Types.OracleUdt.IsDBNull(con, pUdt, "UPDATE_DATE");
if ((UPDATE_DATEIsNull == false)) {
this.UPDATE_DATE = ((System.DateTime)(Oracle.DataAccess.Types.OracleUdt.GetValue(con, pUdt, "UPDATE_DATE")));
}
this.FLEXFIELD_1 = ((string)(Oracle.DataAccess.Types.OracleUdt.GetValue(con, pUdt, "FLEXFIELD_1")));
this.INSERT_DATEIsNull = Oracle.DataAccess.Types.OracleUdt.IsDBNull(con, pUdt, "INSERT_DATE");
if ((INSERT_DATEIsNull == false)) {
this.INSERT_DATE = ((System.DateTime)(Oracle.DataAccess.Types.OracleUdt.GetValue(con, pUdt, "INSERT_DATE")));
}
this.FLEXFIELD_3 = ((string)(Oracle.DataAccess.Types.OracleUdt.GetValue(con, pUdt, "FLEXFIELD_3")));
this.UPDATE_USER = ((string)(Oracle.DataAccess.Types.OracleUdt.GetValue(con, pUdt, "UPDATE_USER")));
this.FLEXFIELD_2 = ((string)(Oracle.DataAccess.Types.OracleUdt.GetValue(con, pUdt, "FLEXFIELD_2")));
this.ORDER_NOIsNull = Oracle.DataAccess.Types.OracleUdt.IsDBNull(con, pUdt, "ORDER_NO");
if ((ORDER_NOIsNull == false)) {
this.ORDER_NO = ((decimal)(Oracle.DataAccess.Types.OracleUdt.GetValue(con, pUdt, "ORDER_NO")));
}
this.FLEXFIELD_4 = ((string)(Oracle.DataAccess.Types.OracleUdt.GetValue(con, pUdt, "FLEXFIELD_4")));
this.INSERT_USER = ((string)(Oracle.DataAccess.Types.OracleUdt.GetValue(con, pUdt, "INSERT_USER")));
this.NOIsNull = Oracle.DataAccess.Types.OracleUdt.IsDBNull(con, pUdt, "NO");
if ((NOIsNull == false)) {
this.NO = ((decimal)(Oracle.DataAccess.Types.OracleUdt.GetValue(con, pUdt, "NO")));
}
this.ITEM_NO = ((string)(Oracle.DataAccess.Types.OracleUdt.GetValue(con, pUdt, "ITEM_NO")));
}
public virtual void ReadXml(System.Xml.XmlReader reader) {
// TODO : Read Serialized Xml Data
}
public virtual void WriteXml(System.Xml.XmlWriter writer) {
// TODO : Serialize object to xml data
}
public virtual XmlSchema GetSchema() {
// TODO : Implement GetSchema
return null;
}
public override string ToString() {
// TODO : Return a string that represents the current object
return "";
}
public static ORDER_LINE_ROW Parse(string str) {
// TODO : Add code needed to parse the string and get the object represented by the string
return new ORDER_LINE_ROW();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool p)
{
if (p == true)
{
GC.SuppressFinalize(this);
}
}
}
// Factory to create an object for the above class
[OracleCustomTypeMappingAttribute("ESIPARIS.ORDER_LINE_ROW")]
public class ORDER_LINE_ROWFactory : IOracleCustomTypeFactory ,IDisposable {
public virtual IOracleCustomType CreateObject() {
ORDER_LINE_ROW obj = new ORDER_LINE_ROW();
return obj;
}
public void Dispose()
{
}
}