Utilizing Oracle’s latest ODP for .NET the following is one implementation of the SDO_DIM_ARRAY and SDO_DIM_ELEMENT type(s) as a .NET class.
This one is easy to explain. I needed to use SDO_MIGRATE.TO_CURRENT to fix some ORA-13367: wrong orientation for interior/exterior rings errors. So I needed SDO_DIM_ARRAY and thusly SDO_DIM_ELEMENT because SDO_MIGRATE.TO_CURRENT requires a SDO_DIM_ARRAY as a parameter. I have included my method of utilizing SDO_MIGRATE.TO_CURRENT after the class definitions.
Source code (C#):
As you see, it utilizes both sdogeometry and sdodimarray...
using System;
using System.Collections;
using System.Text;
using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;
namespace NetSdoDimArray
{
///
/// ////////////////////////////////////
/// sdodimarray
/// ////////////////////////////////////
///
public class sdodimarray : IOracleCustomType, INullable
{
[OracleObjectMapping(0)]
public sdodimelement[] _dimelements;
private bool m_bIsNull;
public bool IsNull
{
get
{
return m_bIsNull;
}
}
public sdodimelement[] DimElements
{
get
{
return _dimelements;
}
set
{
_dimelements = value;
}
}
public static sdodimarray Null
{
get
{
sdodimarray obj = new sdodimarray();
obj.m_bIsNull = true;
return obj;
}
}
public override string ToString()
{
if (m_bIsNull)
return "sdodimarray.Null";
else
{
StringBuilder sb = new StringBuilder();
foreach (sdodimelement i in _dimelements)
{
sb.Append("sdodimelement(");
sb.Append(i._dimname + "=");
sb.Append(string.Format("{0:0.#####}", i._lb));
sb.Append(",");
sb.Append(string.Format("{0:0.#####}", i._ub));
sb.Append(",Tol=");
sb.Append(i._tolerance.ToString());
sb.Append(")");
}
return sb.ToString();
}
}
public void ToCustomObject(OracleConnection con, IntPtr pUdt)
{
_dimelements = (sdodimelement[])OracleUdt.GetValue(con, pUdt, 0);
}
public void FromCustomObject(OracleConnection con, IntPtr pUdt)
{
OracleUdt.SetValue(con, pUdt, 0, _dimelements);
}
}
[OracleCustomTypeMapping("MDSYS.SDO_DIM_ARRAY")]
public class sdodimarrayFactory : IOracleArrayTypeFactory, IOracleCustomTypeFactory
{
// IOracleCustomTypeFactory Inteface
public IOracleCustomType CreateObject()
{
return new sdodimarray();
}
// IOracleArrayTypeFactory.CreateArray Inteface
public Array CreateArray(int numElems)
{
return new sdodimelement[numElems];
}
// IOracleArrayTypeFactory.CreateStatusArray
public Array CreateStatusArray(int numElems)
{
// An OracleUdtStatus[] is not required to store null status information
// if there is no NULL attribute data in the element array
return null;
}
}
///
/// ////////////////////////////////////
/// sdodimelement
/// ////////////////////////////////////
///
public class sdodimelement : IOracleCustomType, INullable
{
[OracleObjectMapping(0)]
public string _dimname;
[OracleObjectMapping(1)]
public double _lb;
[OracleObjectMapping(2)]
public double _ub;
[OracleObjectMapping(3)]
public double _tolerance;
private bool m_bIsNull;
public bool IsNull
{
get
{
return m_bIsNull;
}
}
public static sdodimelement Null
{
get
{
sdodimelement obj = new sdodimelement();
obj.m_bIsNull = true;
return obj;
}
}
public override string ToString()
{
if (m_bIsNull)
return "sdodimelement.Null";
else
{
StringBuilder sb = new StringBuilder();
sb.Append("sdodimelement(");
sb.Append(_dimname + "=");
sb.Append(string.Format("{0:0.#####}", _lb));
sb.Append(",");
sb.Append(string.Format("{0:0.#####}", _ub));
sb.Append(",Tol=");
sb.Append(_tolerance.ToString());
sb.Append(")");
return sb.ToString();
}
}
public void ToCustomObject(OracleConnection con, IntPtr pUdt)
{
_dimname = (string)OracleUdt.GetValue(con, pUdt, 0);
_lb = (double)OracleUdt.GetValue(con, pUdt, 1);
_ub = (double)OracleUdt.GetValue(con, pUdt, 2);
_tolerance = (double)OracleUdt.GetValue(con, pUdt, 3);
}
public void FromCustomObject(OracleConnection con, IntPtr pUdt)
{
OracleUdt.SetValue(con, pUdt, 0, _dimname);
OracleUdt.SetValue(con, pUdt, 1, _lb);
OracleUdt.SetValue(con, pUdt, 2, _ub);
OracleUdt.SetValue(con, pUdt, 3, _tolerance);
}
}
[OracleCustomTypeMapping("MDSYS.SDO_DIM_ELEMENT")]
public class sdodimelementFactory : IOracleCustomTypeFactory
{
// IOracleCustomTypeFactory Inteface
public IOracleCustomType CreateObject()
{
sdodimelement sdodimelement = new sdodimelement();
return sdodimelement;
}
}
}
public static sdogeometry MigrateToCurrentSP(string connectstring, sdogeometry _geoIn, sdodimarray _toleranceIn)
{
//ORA-13367: wrong orientation for interior/exterior rings
sdogeometry rtnval = null;
using (OracleConnection conn = new OracleConnection(connectstring))
{
using (OracleCommand dbcmd = conn.CreateCommand())
{
dbcmd.CommandType = CommandType.StoredProcedure;
dbcmd.CommandText = "SDO_MIGRATE.TO_CURRENT";
OracleParameter cParm1 = new OracleParameter();
cParm1.ParameterName = "geometry";
cParm1.OracleDbType = OracleDbType.Object;
cParm1.Value = _geoIn;
cParm1.UdtTypeName = "MDSYS.SDO_GEOMETRY";
cParm1.Direction = ParameterDirection.Input;
OracleParameter cParm2 = new OracleParameter();
cParm2.ParameterName = "tolerance";
cParm2.OracleDbType = OracleDbType.Object;
cParm2.Value = _toleranceIn;
cParm2.UdtTypeName = "MDSYS.SDO_DIM_ARRAY";
cParm2.Direction = ParameterDirection.Input;
OracleParameter cParm3 = new OracleParameter();
cParm3.ParameterName = "RETURNVALUE";
cParm3.OracleDbType = OracleDbType.Object;
cParm3.UdtTypeName = "MDSYS.SDO_GEOMETRY";
cParm3.Direction = ParameterDirection.ReturnValue;
// Note the order
dbcmd.Parameters.Add(cParm3);
dbcmd.Parameters.Add(cParm1);
dbcmd.Parameters.Add(cParm2);
try
{
conn.Open();
dbcmd.ExecuteNonQuery();
rtnval = (sdogeometry)dbcmd.Parameters["RETURNVALUE"].Value;
}
catch (Exception _Ex)
{
throw (_Ex); // Actually rethrow
}
finally
{
if (conn != null && conn.State == ConnectionState.Open)
{
conn.Close();
}
}
}//using cmd
}//using conn
return rtnval;
}
I get memory leaks using udt this way
ReplyDeleteIt seems like oracle is not releasing the reference to the data in the OracleUdt
Have you seen that
I am sending large amount of data to a procedure
so in a short time the size of my application becomes big, windows is then not behaving in a good way
I am glad if there is a solution to this
/Bengt
Here is some code I have done
ReplyDeleteFirst the array class
public class UdtArray T : IOracleCustomType, INullable
where T : IOracleCustomType
{
[OracleObjectMapping(0)]
public T[] _listElements;
private bool m_bIsNull;
public bool IsNull
{
get { return m_bIsNull; }
}
public T[] ListElements
{
get { return _listElements; }
set { _listElements = value; }
}
public static UdtArray T Null
{
get
{
UdtArray T obj = new UdtArray T();
obj.m_bIsNull = true;
return obj;
}
}
public override string ToString()
{
if (m_bIsNull)
{
return "UdtArray.Null";
}
else
{
StringBuilder sb = new StringBuilder();
foreach (T i in _listElements)
{
sb.Append("UdtArray(");
sb.Append(i.ToString() + "=");
sb.Append(")");
}
return sb.ToString();
}
}
public virtual void ToCustomObject(OracleConnection con, IntPtr pUdt)
{
_listElements = (T[])OracleUdt.GetValue(con, pUdt, 0);
}
public virtual void FromCustomObject(OracleConnection con, IntPtr pUdt)
{
OracleUdt.SetValue(con, pUdt, 0, (T[])_listElements);
}
public Array CreateStatusArray(int numElems)
{
return null;
}
}
/////////
// the data in the array
public class UdtTransDetail : IOracleCustomType, INullable
{
[OracleObjectMapping(0)]
public long TransdetailId;
[OracleObjectMapping(1)]
public long TransactionId;
[OracleObjectMapping(2)]
public DateTime ReportedStartTime;
[OracleObjectMapping(3)]
public DateTime ReportedEndTime;
[OracleObjectMapping(4)]
public DateTime RatedStartTime;
[OracleObjectMapping(5)]
public DateTime RatedEndTime;
[OracleObjectMapping(6)]
public decimal Units;
public UdtTransDetail()
{
}
public UdtTransDetail(UtTransDetailDataMD2 data, long transactionid, long transdetailid)
{
TransdetailId = transdetailid;
TransactionId = transactionid;
ReportedStartTime = data.ReportedStartTime;
ReportedEndTime = data.ReportedEndTime;
RatedStartTime = data.RatedStartTime; // this will be set in db just a dummy add
RatedEndTime = data.RatedEndTime; // this will be set in db just a dummy add
Units = data.Units;
}
private bool m_bIsNull;
public bool IsNull
{
get { return m_bIsNull; }
}
public static UdtTransDetail Null
{
get
{
UdtTransDetail obj = new UdtTransDetail();
obj.m_bIsNull = true;
return obj;
}
}
public override string ToString()
{
if (m_bIsNull)
{
return "UdtTransDetail.Null";
}
else
{
StringBuilder sb = new StringBuilder();
sb.Append("UdtTransDetail(");
sb.Append(")");
return sb.ToString();
}
}
public virtual void ToCustomObject(OracleConnection con, IntPtr pUdt)
{
TransdetailId = (long)OracleUdt.GetValue(con, pUdt, 0);
TransactionId = (long)OracleUdt.GetValue(con, pUdt, 1);
ReportedStartTime = (DateTime)OracleUdt.GetValue(con, pUdt, 2);
ReportedEndTime = (DateTime)OracleUdt.GetValue(con, pUdt, 3);
RatedStartTime = (DateTime)OracleUdt.GetValue(con, pUdt, 4);
RatedEndTime = (DateTime)OracleUdt.GetValue(con, pUdt, 5);
Units = (decimal)OracleUdt.GetValue(con, pUdt, 6);
}
public virtual void FromCustomObject(OracleConnection con, IntPtr pUdt)
{
OracleUdt.SetValue(con, pUdt, 0, TransdetailId);
OracleUdt.SetValue(con, pUdt, 1, TransactionId);
OracleUdt.SetValue(con, pUdt, 2, ReportedStartTime);
OracleUdt.SetValue(con, pUdt, 3, ReportedEndTime);
OracleUdt.SetValue(con, pUdt, 4, RatedStartTime);
OracleUdt.SetValue(con, pUdt, 5, RatedEndTime);
OracleUdt.SetValue(con, pUdt, 6, Units);
}
}
////the factory
/// For Details
public class DetailUdtFactory : IOracleCustomTypeFactory
{
public IOracleCustomType CreateObject()
{
UdtTransDetail sdodimelement = new UdtTransDetail();
return sdodimelement;
}
}
public class DetailUdtArrayFactory : IOracleArrayTypeFactory, IOracleCustomTypeFactory
{
public IOracleCustomType CreateObject()
{
return new UdtArray UdtTransDetail();
}
public Array CreateArray(int numElems)
{
return new UdtTransDetail[numElems];
}
public Array CreateStatusArray(int numElems)
{
return null;
}
}
The procedure has six arays as argument this is
I use the UDTArray for all of them
Anyone knows this ???
/Bengt