Oracle 9 provides real nice options to keep collection of values.
 
 SYS.ODCINUMBERLIST – VARRAY(32767) of NUMBER
 SYS.ODCIVARCHAR2LIST – VARRAY(32767) OF VARCHAR2(4000)
 
 Using these we can pass collection of Numbers / Strings to Stored Procedure.
 
 Now, how could we use this at .Net Layer?
 
 Here are the steps,
 
 Create an Oracle Custom Type for replicate ODCINUMBERLIST / ODCIVARCHAR2LIST.
 
 Map it to appropriate Oracle Types.
 
 Use this Custom Type to pass parameter.
 
 Create Oracle Custom Type.
 
 Make sure a reference “Oracle.DataAccess”.
 
- using System;  
- using Oracle.DataAccess.Client;  
- using Oracle.DataAccess.Types;  
- namespace MyDataAccessUtilities.OracleCustomTypes  
- {  
-     public class OdciNumberList: IOracleCustomType, INullable  
-     {  
-         [OracleArrayMapping] public Int32[] Array;  
-         public OracleUdtStatus[] StatusArray  
-         {  
-             get;  
-             set;  
-         }  
-         public void FromCustomObject(OracleConnection con, IntPtr pUdt)  
-         {  
-             OracleUdt.SetValue(con, pUdt, 0, Array, StatusArray);  
-         }  
-         public void ToCustomObject(OracleConnection con, IntPtr pUdt)  
-         {  
-             object objectStatusArray;  
-                 Array = (Int32[]) OracleUdt.GetValue(con, pUdt, 0, out objectStatusArray);  
-             StatusArray = (OracleUdtStatus[]) objectStatusArray;  
-         }  
-         public bool IsNull  
-         {  
-             get;  
-             private set;  
-         }  
-         public static OdciNumberList Null  
-         {  
-             get  
-             {  
-                 var odciNumberList = new OdciNumberList();  
-                 odciNumberList.IsNull = true;  
-                 return odciNumberList;  
-             }  
-         }  
-     }  
-     [OracleCustomTypeMapping("SYS.ODCINUMBERLIST")]  
-     public class OdciNumberListFactory: IOracleCustomTypeFactory, IOracleArrayTypeFactory  
-     {  
-         public IOracleCustomType CreateObject()  
-         {  
-             return new OdciNumberList();  
-         }  
-         public Array CreateArray(int numElems)  
-         {  
-             return new Int32[numElems];  
-         }  
-         public Array CreateStatusArray(int numElems)  
-         {  
-             return new OracleUdtStatus[numElems];  
-         }  
-     }  
- }  
 - using System;  
- using System.Collections.Generic;  
- using System.Data;  
- using Oracle.DataAccess.Client;  
- namespace MyDataAccessUtilities.OracleCustomTypes  
- {  
-     public static class OracleParameterExtension  
-     {  
-         public static OracleParameter GenerateOdciNumberListParameter(this OracleParameter oracleParameter, string parameterName, List < Int32 > numberList, ParameterDirection parameterDirection = ParameterDirection.Input)  
-         {  
-             oracleParameter.OracleDbType = OracleDbType.Array;  
-             oracleParameter.ParameterName = parameterName;  
-             oracleParameter.UdtTypeName = "SYS.ODCINUMBERLIST";  
-             oracleParameter.Direction = parameterDirection;  
-             if (parameterDirection == ParameterDirection.Input || parameterDirection == ParameterDirection.InputOutput)  
-             {  
-                 var numberArray = new OdciNumberList();  
-                 if (numberList != null)  
-                 {  
-                     numberArray.Array = numberList.ToArray();  
-                 }  
-                 oracleParameter.Value = numberArray;  
-             }  
-             return oracleParameter;  
-         }  
-         public static List < int > GetOdciNumberListParameterValue(this OracleParameter oracleParameter)  
-         {  
-             var result = new List < int > ();  
-             if (oracleParameter.Value is OdciNumberList)  
-             {  
-                 var parameter = oracleParameter.Value as OdciNumberList;  
-                 if (parameter.Array != null) result.AddRange(parameter.Array);  
-             }  
-             return result;  
-         }  
-     }  
- }  
 
 Here is sample procedure which takes SYS.ODCINUMBERLIST as input parameter:
 - CREATE OR REPLACE  
- PROCEDURE GETEMPLOYEES(PIN_EMPLOYEEIDS SYS.ODCINUMBERLIST, POUT_EMPLOYEES OUT SYS_REFCURSOR)  
- AS  
- BEGIN  
- SELECT EMP.*FROM EMPLOYEE EMP  
- JOIN TABLE(PIN_EMPLOYEEIDS) IDS  
- ON EMP.EMP_ID = IDS.COLUMN_VALUE;  
- END  
 - var employeeIds = new List < int >  
- {  
-     100,  
-     110,  
-     115,  
-     116,  
-     117,  
-     118,  
-     119,  
-     120,  
-     124,  
-     125  
- };  
- using(var con = new OracleConnection("Connection sting here"))  
- {  
-     con.Open();  
-     using(var command = new OracleCommand("GetEmployees", con))  
-     {  
-         command.Parameters.Add(new OracleParameter().GenerateOdciNumberListParameter("PIN_EMPLOYEEIDS", employeeIds, ParameterDirection.Input));  
-         command.Parameters.Add(new OracleParameter("POUT_EMPLOYEES", OracleDbType.RefCursor, ParameterDirection.Output));  
-         using(var reader = command.ExecuteReader())  
-         {  
-               
-         }  
-     }  
- }