C#:将用户定义的类型传递给Oracle存储过程

时间:2009-06-11 10:38:12

标签: c# oracle stored-procedures

参考Oracle: Variable number of parameters to a stored procedure

我有一个存储过程可以将多个用户插入到User表中。该表定义如下:

CREATE TABLE "USER" 
   (
   "Name" VARCHAR2(50),
   "Surname" VARCHAR2(50),
   "Dt_Birth" DATE,
   )

插入多个用户的存储过程是:

type userType is record (
  name varchar2(100),
...
);

type userList is table of userType index by binary_integer;

procedure array_insert (p_userList  in userList) is
begin
    forall i in p_userList.first..p_userList.last
    insert into users (username) values (p_userList(i) );
end array_insert;

如何从C#调用存储过程传递userType的userList? 感谢

3 个答案:

答案 0 :(得分:8)

以下是我在Oracle中使用存储过程的帮助程序:

internal class OracleDataHelper
{
    #region Variables
    private static readonly string _connectionString;
    #endregion

    #region Constructors
    static OracleDataHelper()
    {
        //_connectionString = ConfigurationManager.ConnectionStrings["..."]
        //    .ConnectionString;
    }
    #endregion

    public static object ExecuteScalar(string query)
    {
        object result;
        using (OracleConnection conn = new OracleConnection(ConnectionString))
        {
            conn.Open();
            OracleCommand command = new OracleCommand(query, conn);
            command.CommandType = CommandType.Text;

            result = command.ExecuteScalar();

            command.Dispose();
            conn.Close();
        }

        return result;
    }

    public static object ExecuteScalar(
        string query, 
        params object[] parameters)
    {
        object result;
        using (OracleConnection conn = new OracleConnection(ConnectionString))
        {
            conn.Open();
            OracleCommand command = new OracleCommand(query, conn);
            command.CommandType = CommandType.Text;
            command.Parameters.AddRange(
                ConvertParameters(parameters)
            );

            result = command.ExecuteScalar();

            command.Dispose();
            conn.Close();
        }

        return result;
    }

    public static int ExecuteNonQuery(string query)
    {
        return ExecuteNonQuery(query, new List<OracleParameter>());
    }

    public static int ExecuteNonQuery(
        string query, 
        List<OracleParameter> parameters)
    {
        int result = 0;

        using (OracleConnection conn = new OracleConnection(ConnectionString))
        {
            conn.Open();
            OracleCommand command = new OracleCommand(query, conn);
            command.CommandType = CommandType.Text;
            command.BindByName = true;
            command.Parameters.AddRange(
                ConvertParameters(parameters.ToArray())
            );

            result = command.ExecuteNonQuery();

            command.Dispose();
            conn.Close();
        }

        return result;
    }

    public static int ExecuteNonQuery(
        string query,
        params object[] parameters)
    {
        int result = 0;
        using (OracleConnection conn = new OracleConnection(ConnectionString))
        {
            conn.Open();
            OracleCommand command = new OracleCommand(query, conn);
            command.BindByName = true;
            command.CommandType = CommandType.Text;
            command.Parameters.AddRange(ConvertParameters(parameters));

            result = command.ExecuteNonQuery();

            command.Dispose();
            conn.Close();
        }

        return result;
    }

    public static OracleDataReader ExecuteReader(
        OracleConnection conn,
        string commandText
        )
    {
        OracleCommand command = new OracleCommand(commandText, conn);

        return command.ExecuteReader();
    }

    public static IDataReader ExecuteReader(
        OracleConnection conn, 
        string spName, 
        out List<OracleParameter> outParameters, 
        params object[] parameters)
    {
        throw new NotImplementedException();
    }

    public static int ExecuteProcedure(
        string spName,
        out OutputParameters outputParameters,
        params object[] parameters)
    {
        int result = 0;

        using (OracleConnection conn = new OracleConnection(ConnectionString))
        {
            conn.Open();
            OracleCommand command = new OracleCommand(spName, conn);
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.AddRange(ConvertParameters(parameters));

            result = command.ExecuteNonQuery();
            outputParameters = GetOutputParameters(command.Parameters);

            command.Dispose();
            conn.Close();
        }

        return result;
    }

    public static int ExecuteProcedure(
        string spName,
        params object[] parameters)
    {
        int result = 0;

        using (OracleConnection conn = new OracleConnection(ConnectionString))
        {
            conn.Open();
            OracleCommand command = new OracleCommand(spName, conn);
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.AddRange(ConvertParameters(parameters));

            result = command.ExecuteNonQuery();

            command.Dispose();
            conn.Close();
        }

        return result;
    }

    public static OracleDataReader ExecuteProcedure(
        OracleConnection conn,
        string spName,
        out OutputParameters outputParameters,
        params object[] parameters
        )
    {
        OracleCommand command = new OracleCommand(spName, conn);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.AddRange(ConvertParameters(parameters));

        OracleDataReader reader = command.ExecuteReader();
        outputParameters = GetOutputParameters(command.Parameters);
        command.Dispose();

        return reader;
    }

    public static OracleDataReader ExecuteProcedure(
        OracleConnection conn,
        string spName,
        params object[] parameters
        )
    {
        OracleCommand command = new OracleCommand(spName, conn);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.AddRange(ConvertParameters(parameters));

        OracleDataReader reader = command.ExecuteReader();
        command.Dispose();

        return reader;
    }

    private static OracleParameter[] ConvertParameters(object[] parameters)
    {
        parameters = parameters ?? new object[] { };

        int parametersCount = parameters.Length;
        OracleParameter[] parametersArray = 
            new OracleParameter[parametersCount];

        for (int i = 0; i < parametersCount; i++)
        {
            object parameter = parameters[i];
            OracleParameter oracleParameter;

            if (parameter is OracleParameter)
            {
                oracleParameter = (OracleParameter)parameter;
                if (null == oracleParameter.Value)
                {
                    oracleParameter.Value = DBNull.Value;
                }
            }
            else
            {
                oracleParameter = new OracleParameter();

                oracleParameter.Value = parameter == null ?
                    DBNull.Value :
                    parameter;
            }

            // adding udt mapping for the parameter
            if (oracleParameter.Value != null && 
                oracleParameter.Value is IOracleCustomTypeFactory)
            {
                MemberInfo info = oracleParameter.Value.GetType();
                OracleCustomTypeMappingAttribute[] attributes =  
                        info.GetCustomAttributes(
                    typeof(OracleCustomTypeMappingAttribute), 
                        false
                    ) as OracleCustomTypeMappingAttribute[];
                if (null != attributes && attributes.Length > 0)
                {
                    oracleParameter.UdtTypeName = attributes[0].UdtTypeName;
                }
            }

            parametersArray[i] = oracleParameter;
        }

        return parametersArray;
    }

    private static OutputParameters GetOutputParameters(
        OracleParameterCollection parameters)
    {
        OutputParameters outputParameters = new OutputParameters();
        foreach (OracleParameter parameter in parameters)
        {
            if (parameter.Direction == ParameterDirection.Output)
                outputParameters.Add(parameter);
        }

        return outputParameters;
    }

    internal static string ConnectionString
    {
        get { return _connectionString; }
    }
}

这些方法适用于UDT,也适用于简单的参数。

以下是UDT实体的示例:

[Serializable]
[OracleCustomTypeMappingAttribute("MDSYS.SDO_GEOMETRY")]
public class SdoGeometry : IOracleCustomTypeFactory, 
                           IOracleCustomType, 
                           ICloneable, INullable
{
    #region Variables
    private int _sdoGType;
    private int _sdoSrid;
    private SdoPoint _sdoPoint;
    private SdoElemInfo _sdoElemInfo;
    private SdoOrdinates _sdoOrdinate;

    private bool _sdoGTypeIsNull;
    private bool _sdoSridIsNull;
    #endregion

    #region Properties
    [OracleObjectMappingAttribute("SDO_GTYPE")]
    public int SdoGType
    {
        get { return _sdoGType; }
        set
        {
            _sdoGType = value;
            _sdoGTypeIsNull = false;
        }
    }

    public SdoGeometryType SdoGeometryType
    {
        get { return (Entities.Geometry.SdoGeometryType)(SdoGType % 100); }
    }

    public int Dimensions
    {
        get { return (int)(SdoGType / 1000); }
    }

    public int LrsDimensions
    {
        get { return (int)((SdoGType / 100) % 10); }
    }

    [OracleObjectMappingAttribute("SDO_SRID")]
    public int SdoSrid
    {
        get { return _sdoSrid; }
        set
        {
            _sdoSrid = value;
            _sdoSridIsNull = false;
        }
    }

    [OracleObjectMappingAttribute("SDO_POINT")]
    public SdoPoint SdoPoint
    {
        get { return _sdoPoint; }
        set { _sdoPoint = value; }
    }

    [OracleObjectMappingAttribute("SDO_ELEM_INFO")]
    public SdoElemInfo SdoElemInfo
    {
        get { return _sdoElemInfo; }
        set { _sdoElemInfo = value; }
    }

    [OracleObjectMappingAttribute("SDO_ORDINATES")]
    public SdoOrdinates SdoOrdinates
    {
        get { return _sdoOrdinate; }
        set { _sdoOrdinate = value; }
    }

    public static SdoGeometry Null
    {
        get
        {
            SdoGeometry obj = new SdoGeometry();

            return obj;
        }
    }
    #endregion

    #region Constructors
    public SdoGeometry()
    {
        _sdoGTypeIsNull = true;
        _sdoSridIsNull = true;
        _sdoElemInfo = SdoElemInfo.Null;
        _sdoOrdinate = SdoOrdinates.Null;
        _sdoPoint = SdoPoint.Null;
    }

    public SdoGeometry(SdoGeometry obj)
    {
        if (obj != null && this != obj)
        {
            SdoGType = obj.SdoGType;
            SdoSrid = obj.SdoSrid;
            SdoPoint = (SdoPoint)obj.SdoPoint.Clone();
            SdoElemInfo = (SdoElemInfo)obj.SdoElemInfo.Clone();
            SdoOrdinates = (SdoOrdinates)obj.SdoOrdinates.Clone();
        }
    }

    public SdoGeometry(
        int gType,
        int srid,
        SdoPoint point,
        SdoElemInfo elemInfo,
        SdoOrdinates ordinate)
    {
        SdoGType = gType;
        SdoSrid = srid;
        SdoPoint = (SdoPoint)point.Clone();
        SdoElemInfo = (SdoElemInfo)elemInfo.Clone();
        SdoOrdinates = (SdoOrdinates)ordinate.Clone();
    }
    #endregion

    #region ICloneable Members
    public object Clone()
    {
        return new SdoGeometry(this);
    }
    #endregion

    #region IOracleCustomType Members
    public void FromCustomObject(OracleConnection con, IntPtr pUdt)
    {
        if (!_sdoGTypeIsNull)
            OracleUdt.SetValue(con, pUdt, "SDO_GTYPE", SdoGType);
        if (!SdoOrdinates.IsNull)
            OracleUdt.SetValue(con, pUdt, "SDO_ORDINATES", SdoOrdinates);
        if (!SdoElemInfo.IsNull)
            OracleUdt.SetValue(con, pUdt, "SDO_ELEM_INFO", SdoElemInfo);
        if (!_sdoSridIsNull)
            OracleUdt.SetValue(con, pUdt, "SDO_SRID", SdoSrid);
        else
            OracleUdt.SetValue(con, pUdt, "SDO_SRID", DBNull.Value);
        if (!SdoPoint.IsNull)
            OracleUdt.SetValue(con, pUdt, "SDO_POINT", SdoPoint);
    }

    public void ToCustomObject(OracleConnection con, IntPtr pUdt)
    {
        object sdoGType = OracleUdt.GetValue(con, pUdt, "SDO_GTYPE");
        _sdoGTypeIsNull = sdoGType == null || sdoGType is DBNull;
        if (!_sdoGTypeIsNull)
            SdoGType = (int)sdoGType;
        SdoOrdinates = 
            (SdoOrdinates)OracleUdt.GetValue(con, pUdt, "SDO_ORDINATES");
        SdoElemInfo = 
            (SdoElemInfo)OracleUdt.GetValue(con, pUdt, "SDO_ELEM_INFO");
        object sdoSrid = OracleUdt.GetValue(con, pUdt, "SDO_SRID");
        if (!(sdoSrid == null || sdoSrid is DBNull))
            SdoSrid = (int)sdoSrid;
        SdoPoint = (SdoPoint)OracleUdt.GetValue(con, pUdt, "SDO_POINT");
    }
    #endregion

    #region INullable Members
    public bool IsNull
    {
        get { return _sdoGTypeIsNull; }
    }
    #endregion

    #region IOracleCustomTypeFactory Members
    public IOracleCustomType CreateObject()
    {
        return new SdoGeometry();
    }
    #endregion
}

P.S。在我的项目期间,Oracle发布了3个版本的ODP.NET。有趣的是:适用于2.111.6.10版本的Oracle.DataAcess.dll的代码根本不适用于2.111.6.20!

现在不知道哪个版本的ODP.NET是实际的,但我上面发布的样本与2.111.6.10一致。

希望这会有所帮助。祝你好运!

答案 1 :(得分:4)

经过多次错误启动后,此post here保存了我的培根(绑定到TABLE OF VARCHAR2(100)的UDT。

显着点

  • 创建一个类来保存嵌套/ UDT类型的数组(即varchar2(100)的字符串数组)
    • 该类必须实现IOracleCustomTypeINullable接口。
    • 它还需要一个属性来保存数组(即string[]),并且该属性必须使用OracleArrayMapping属性进行标记。
  • 创建第二个实现IOracleArrayTypeFactoryIOracleCustomTypeFactory接口的UDT Factory类。它需要以下方法
    • CreateObject - 创建存储类的新对象
    • CreateArray - 分配要在存储类中设置的字符串数组
    • CreateStatusArray - 保留每行的状态
  • 工厂类还必须标有OracleCustomTypeMapping("SCHEMA.UDT_TYPE"),其中SCHEMA.UDT_TYPE符合您的UDT类型,即CREATE TYPE SCHEMA.UDT_TYPE AS TABLE OF VARCHAR2(100)

相比之下,参数的绑定很简单:

   var oracleArray = new MyArrayStorageClass
      {
         Array = new string[] {"Hello", "World"}
      };
   command.CommandType = CommandType.StoredProcedure;
   var param = new OracleParameter("ip_parameterName", OracleDbType.Array)
      {
         // Case sensitive match to the `OracleCustomTypeMapping` on the factory
         UdtTypeName = "SCHEMA.UDT_TYPE", 
         Value = oracleArray,
         Direction = ParameterDirection.Input,
      };
   command.Parameters.Add(param);

答案 2 :(得分:-2)

ODP.net支持用户定义的类型。 http://www.oracle.com/technology/tech/windows/odpnet/index.html

谷歌的例子或阅读手册。