2009-06-11 35 views
7

Với tham chiếu đến Oracle: Variable number of parameters to a stored procedureC#: Vượt qua một kiểu người dùng định nghĩa để một thủ tục được lưu trữ Oracle

Tôi có s lưu trữ thủ tục để chèn nhiều người dùng vào một bảng tài khoản. Bảng này được định nghĩa như sau:

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

các thủ tục lưu trữ để chèn nhiều người dùng là:

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; 

Làm thế nào tôi có thể gọi thủ tục lưu trữ từ C# thông qua một danh sách người dùng của loại người dùng? Cảm ơn

Trả lời

6

Đây là một helper Tôi từng làm việc với các thủ tục được lưu trữ trong 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; } 
    } 
} 

Những phương pháp làm việc với UDT cũng như họ làm việc với các thông số đơn giản.

Dưới đây là một ví dụ về UDT thực thể:

[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 
} 

T.B. Trong dự án của tôi, Oracle đã phát hành 3 phiên bản ODP.NET. Điều thú vị: mã làm việc cho phiên bản 2.111.6.10 của Oracle.DataAcess.dll không hoạt động với 2.111.6.20!

Không biết phiên bản ODP.NET nào là thực tế nhưng các mẫu tôi đã đăng ở trên hoạt động tốt với 2.111.6.10.

Hy vọng điều này sẽ hữu ích. Chúc may mắn!

+0

Tôi đang cố gắng viết một hàm trợ giúp tương tự và tôi đặc biệt quan tâm đến chức năng "ConvertParameters" của bạn. trả về một mảng các OracleParameters ... nhưng có vẻ như một phần của mã trong hàm đó bị thiếu. Tôi nhận ra nó đã được một thời gian kể từ khi đăng bài này, nhưng là có bất kỳ cơ hội bạn có thể điền vào các phần thiếu? – Mike

+1

@Mike: có vẻ như, trình phân tích cú pháp đã thực hiện điều gì đó khủng khiếp với mã tôi đã đăng, vì vậy tôi đã cập nhật bài đăng. Có vẻ như phương pháp bạn hỏi là ok. – Alex

+0

Cảm ơn! Điều đó rất hữu ích. – Mike

2

Sau nhiều lần khởi động sai, post here lưu bacon của tôi (liên kết với UDT TABLE OF VARCHAR2(100)).

điểm nổi bật

  • Tạo một lớp học để tổ chức một Mảng của của các loại lồng/UDT (tức là một mảng của chuỗi cho varchar2(100) của bạn)
    • Các lớp phải thực hiện IOracleCustomTypeINullable giao diện.
    • Cũng cần có thuộc tính để giữ mảng (ví dụ: string[]) và thuộc tính phải được đánh dấu bằng thuộc tính OracleArrayMapping.
  • Tạo lớp nhà máy UDT thứ hai triển khai giao diện IOracleArrayTypeFactory, IOracleCustomTypeFactory.Nó cần các phương pháp sau
    • CreateObject - tạo ra một đối tượng mới của lớp lưu trữ
    • CreateArray - phân bổ mảng các chuỗi được thiết lập trong lớp lưu trữ
    • CreateStatusArray - một tình trạng mỗi hàng được giữ lại
  • lớp nhà máy cũng phải được đánh dấu bằng OracleCustomTypeMapping("SCHEMA.UDT_TYPE") nơi SCHEMA.UDT_TYPE phù hợp với loại UDT của bạn, tức là CREATE TYPE SCHEMA.UDT_TYPE AS TABLE OF VARCHAR2(100)

Để so sánh, liên kết trên tham số rất đơn giản:

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); 
Các vấn đề liên quan