2009-06-11 21 views
7

Con referencia a Oracle: Variable number of parameters to a stored procedureC#: pasar un tipo definido por el usuario a un procedimiento almacenado de Oracle

tengo s procedimiento para insertar múltiples usuarios en una tabla de usuario almacenados. La tabla se define como:

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

el procedimiento almacenado para insertar múltiples usuarios es:

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ómo puedo llamar al procedimiento almacenado desde C# pasar un lista_usuarios de userType? Gracias

Respuesta

6

Aquí es un ayudante que solía trabajar con procedimientos almacenados en 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; } 
    } 
} 

Estos métodos funcionan con UDT todo lo bien que funcionan con parámetros simples.

Aquí es un ejemplo de entidad 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. Durante mi proyecto, Oracle lanzó 3 versiones de ODP.NET. Lo interesante: ¡el código que funcionaba para la versión 2.111.6.10 de Oracle.DataAcess.dll no funcionaba para 2.111.6.20 en absoluto!

No sé qué versión de ODP.NET es actual, pero las muestras que publiqué anteriormente funcionan bien con 2.111.6.10.

Espero que esto ayude. ¡Buena suerte!

+0

Estoy intentando escribir un conjunto de funciones de ayuda similares, y estoy particularmente interesado en ver sus "ConvertParameters" función que toma una matriz de objetos y devuelve una matriz de OracleParameters ... pero parece que falta una parte del código en esa función. Me doy cuenta de que ha pasado un tiempo desde esta publicación, pero ¿hay alguna posibilidad de que puedas completar las partes faltantes? – Mike

+1

@Mike: parece que el analizador realizó algo horrible con el código que publiqué, así que actualicé la publicación. Parece que el método que pediste está bien. – Alex

+0

¡Gracias! Eso es muy útil. – Mike

2

Después de muchos inicios en falso, este post here salvó mi tocino (vinculante a un UDT de TABLE OF VARCHAR2(100)).

Los puntos más destacados

  • crear una clase para mantener un matriz de del tipo anidado/UDT (es decir, un array de cadenas para su varchar2(100))
    • La clase debe implementar la IOracleCustomType y INullable interfaces.
    • También necesita una propiedad para contener la matriz (es decir, string[]), y la propiedad debe marcarse con el atributo OracleArrayMapping.
  • Cree una segunda clase UDT Factory que implemente las interfaces IOracleArrayTypeFactory, IOracleCustomTypeFactory.Se necesita los métodos siguientes
    • CreateObject - crea un nuevo objeto de la clase de almacenamiento
    • CreateArray - asigna la matriz de cadenas que se encuentra en la clase de almacenamiento
    • CreateStatusArray - un estado por fila se retiene
  • La clase de fábrica también deben estar marcados con OracleCustomTypeMapping("SCHEMA.UDT_TYPE") donde SCHEMA.UDT_TYPE adecuado para su tipo UDT, a saber CREATE TYPE SCHEMA.UDT_TYPE AS TABLE OF VARCHAR2(100)

En comparación, el aprieto en el parámetro es sencillo:

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); 
Cuestiones relacionadas