2009-06-11 100 views
7

參照Oracle: Variable number of parameters to a stored procedureC#:傳遞一個用戶定義的類型到Oracle存儲過程

我有存儲過程來插入多個用戶到用戶表秒。該表的定義如下:

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#通過用戶類型的用戶列表中的存儲過程? 由於

回答

6

這裏是我以前在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發佈了ODP.NET的3個版本。有趣的是:2.111.6.10版本的Oracle.DataAcess.dll工作的代碼根本無法用於2.111.6.20!

不知道哪個ODP.NET版本現在是實際的,但我上面張貼的樣本2.111.6.10效果很好。

希望這會有所幫助。祝你好運!

+0

我想寫一組類似的輔助功能,而我在看到你的「ConvertParameters」特別感興趣的函數,它接受一個對象數組和返回一個OracleParameters數組......但它看起來像是該函數中的一部分代碼缺失。我意識到自從這篇文章已經有一段時間了,但是有沒有機會填補缺失的部分? – Mike 2011-02-24 22:21:11

2

經過很多假開始,post here保存了我的培根(綁定到UDT TABLE OF VARCHAR2(100))。

要點

  • 創建一個類來保存一個陣列的嵌套/ UDT類型的(即您varchar2(100)字符串數組)
    • 的類必須實現IOracleCustomTypeINullable接口。
    • 它還需要一個屬性來保存陣列(即string[]),並且屬性必須與OracleArrayMapping屬性進行標記。
  • 創建第二個UDT Factory類,該類實現IOracleArrayTypeFactory,IOracleCustomTypeFactory接口。它需要下列方法
    • 的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); 
相關問題