2009-06-11 3 views
7

Con riferimento alla Oracle: Variable number of parameters to a stored procedureC#: Passa un tipo definito dall'utente a un Oracle stored procedure

devo s procedura per inserire più utenti in una tabella utente memorizzati. La tabella è definito come:

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

La stored procedure per inserire più utenti è:

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; 

Come posso chiamare la stored procedure da C# passando un userList di UserType? Grazie

risposta

6

Ecco un aiutante che ho usato per lavorare con le stored procedure in 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; } 
    } 
} 

Questi metodi funzionano con UDT e lavorano con i parametri semplici.

Ecco un esempio di UDT entità:

[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 il mio progetto Oracle ha rilasciato 3 versioni di ODP.NET. La cosa interessante: il codice che ha funzionato per la versione 2.111.6.10 di Oracle.DataAcess.dll non ha funzionato per 2.111.6.20!

Non so quale versione di ODP.NET sia effettiva ora ma gli esempi che ho postato sopra funzionano bene con 2.111.6.10.

Spero che questo aiuti. In bocca al lupo!

+0

Sto cercando di scrivere una serie di funzioni di supporto simili, e sono particolarmente interessato a vedere i vostri "ConvertParameters" funzione che prende una matrice di oggetti e restituisce un array di OracleParameters ... ma sembra che una parte del codice in quella funzione sia mancante. Mi rendo conto che è passato un po 'di tempo da questo post, ma c'è qualche possibilità che tu possa compilare le parti mancanti? – Mike

+1

@ Mike: a quanto pare, il parser ha eseguito qualcosa di orribile con il codice che ho postato, quindi ho aggiornato il post. Sembra che il metodo che hai chiesto sia ok. – Alex

+0

Grazie! Questo è molto utile. – Mike

2

Dopo molte false partenze, questo post here ha salvato il bacon (associazione a un UDT di TABLE OF VARCHAR2(100)).

punti salienti

  • creare una classe di tenere un Array di del tipo annidato/UDT (cioè un array di stringhe per il vostro varchar2(100))
    • La classe deve implementare l'IOracleCustomType e interfacce INullable.
    • Ha anche bisogno di una proprietà per contenere l'array (ad esempio string[]) e la proprietà deve essere contrassegnata con l'attributo OracleArrayMapping.
  • Creare una seconda classe di fabbrica UDT che implementa le interfacce IOracleArrayTypeFactory, IOracleCustomTypeFactory.Essa richiede i seguenti metodi
    • CreateObject - crea un nuovo oggetto della classe di memoria
    • CreateArray - alloca la matrice di stringhe da impostare nella classe di memorizzazione
    • CreateStatusArray - uno stato per ogni riga viene mantenuto
  • La classe fabbrica deve essere inoltre marcate con OracleCustomTypeMapping("SCHEMA.UDT_TYPE") dove SCHEMA.UDT_TYPE corrispondente al tipo di UDT, cioè CREATE TYPE SCHEMA.UDT_TYPE AS TABLE OF VARCHAR2(100)

In confronto, il bind sul parametro è semplice:

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