What we had before was a OracleCommand we were adding parameters to, then we'd run ExecuteReaderAsync on it to get a OracleDataReader. Then we filled lists of different objects by calling a "GetList" method that would take the reader and a method group that returns an object of the same type as the list.
// These parameters need to be in the same order as returned by the procedure.
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("ProcedureTable1", OracleDbType.RefCursor, ParameterDirection.Output);
command.Parameters.Add("ProcedureTable2", OracleDbType.RefCursor, ParameterDirection.Output);
command.Parameters.Add("ProcedureTable3", OracleDbType.RefCursor, ParameterDirection.Output);
OracleDataReader reader = await command.ExecuteReaderAsync() as OracleDataReader;
// These methods need to be called in the same order as the parameters above.
List<Type1> type1s = await GetList(reader, CreateType1, false); // The first item is called with an overload that takes wht
List<Type2> type2s = await GetList(reader, CreateType2);
List<Type3> type3s = await GetList(reader, CreateType3);
The problem, as the commends suggest, is that if the parameters are put out of order we get a database exception instead of data. If the calls to the method groups are placed out of order the list simply fill with empty versions of the class they should contain.
It was suggested to use an ordered list, so I set up a Dictionary to hold DataPackage object with a string name of the procedure in the database package and the method group.
I was easily able to add them all in the right order once, and set up the command parameters.
// These parameter/method pairs need to be in the same order as returned by the procedure.
List<DataPackage> orderedList = new List<DataPackage>
{
new DataPackage<Type1>("Type1ProcedureName", CreateType1MethodGroup, type1List),
new DataPackage<Type2>("Type2ProcedureName", CreateType2MethodGroup, type2List),
new DataPackage<Type3>("Type3ProcedureName", CreateType3MethodGroup, type1List),
};
command.CommandType = CommandType.StoredProcedure;
orderedList.ForEach(p => command.Parameters.Add(p.ProcedureName, OracleDbType.RefCursor, ParameterDirection.Output));
With the classes
public class DataPackage
{
public string ProcedureName { get; protected set; }
public Func<OracleDataReader, object> MethodGroup { get; protected set; }
public virtual void Add(object list)
{
}
}
and
public class DataPackage<T> : DataPackage
{
public DataPackage(string procedureName, Func<OracleDataReader, object> methodGroup, List<T> returnedData)
{
this.ProcedureName = procedureName;
this.MethodGroup = methodGroup;
this.ReturnedData = returnedData;
}
public List<T> ReturnedData { get; set; }
public override void Add (object list)
{
List<T> castList = list as List<T>;
if (castList != null)
{
this.ReturnedData.AddRange(castList);
}
}
}
At least it only needs to be added in order once, and that part works. The part where I haven't been able to figure out is calling the GetList with each method group to fill the data.
orderedList.ForEach(async v =>
{
v.Add(await GetList(reader, v.MethodGroup, false));
});
The problem is when I debug the Add method on DataPackage the list comes in as an object, and it tries to be cast to List but that fails, even though the list parameter is obviously a list and is filled with data. Is there a better way to do this?
I was searching and found the question Cast Object to Generic List and changed the code in the Add method of the typed DataPackage to
public override void Add (object list)
{
IEnumerable castList = list as IEnumerable;
if (castList != null)
{
IEnumerable<T> typedList = castList.OfType<T>();
this.ReturnedData.AddRange(typedList);
}
}
And it works fine.