我正在尝试构建一个通用助手类,它将帮助我翻译"将每个结果集转换为此处所述的类型安全类Handle multiple result from a stored procedure with SqlQuery
对于我的解决方案,我想将以下内容传递给我的助手类(MultiResultsetsHelper):
然后让帮助程序类重新填充填充1.以下是目前的代码:
结果类
public class Set1ReturnDto
{
public int CruiseCount { get; set; }
public string DisplayText { get; set; }
public int DisplayValue { get; set; }
}
public class Set2ReturnDto
{
public string DepartingFrom { get; set; }
public string Port_Code { get; set; }
}
public class DummyReturnDto
{
public DummyReturnDto()
{
Set1 = new List<Set1ReturnDto>();
Set2 = new List<Set2ReturnDto>();
}
public List<Set1ReturnDto> Set1 { get; set; }
public List<Set2ReturnDto> Set2 { get; set; }
}
低级数据库调用
public static DummyReturnDto DonoUspGetSideBarList(DbContext aDbContext, out int aProcResult)
{
SqlParameter procResultParam = new SqlParameter { ParameterName = "@procResult", SqlDbType = SqlDbType.Int, Direction = ParameterDirection.Output };
DbCommand dbCommand = aDbContext.Database.Connection.CreateCommand();
dbCommand.Parameters.Add(procResultParam);
dbCommand.CommandText = "EXEC @procResult = [dbo].[usp_GetSideBarList] ";
dbCommand.Transaction = aDbContext.Database.CurrentTransaction.UnderlyingTransaction;
DbDataReader reader = dbCommand.ExecuteReader();
aProcResult = -1;
// Drop down to the wrapped `ObjectContext` to get access to the `Translate` method
ObjectContext objectContext = ((IObjectContextAdapter)aDbContext).ObjectContext;
List<Type> containedDtos = new List<Type>
{
typeof (List<Set1ReturnDto>),
typeof (List<Set1ReturnDto>)
};
return MultiResultsetsHelper.Process<DummyReturnDto>(reader, objectContext, containedDtos);
}
返回的结果数据集是:
助手类
public static class MultiResultsetsHelper
{
/// <summary>
/// Given a data reader that contains multiple result sets, use the supplied object context to serialise the
/// rows of data in the result set into our property.
/// </summary>
/// <typeparam name="T">Type of the containing object that contains all the various result sets.</typeparam>
/// <param name="aDbReader">Database reader that contains all the result sets returned from the database.</param>
/// <param name="aObjectContext">Data context associated with the data reader.</param>
/// <param name="aContainedDataSetReturnedTypes">
/// List of types in order of which the result sets are contained within the
/// data reader. We will serilize sequentially each result set the data reader contains
/// </param>
/// <returns>Retuns an object representing all the result sets returned by the data reader.</returns>
public static T Process<T>(DbDataReader aDbReader, ObjectContext aObjectContext, List<Type> aContainedDataSetReturnedTypes) where T : new()
{
//What we will be returning
T result = new T();
for (int datasetNdx = 0; datasetNdx < aContainedDataSetReturnedTypes.Count; datasetNdx++)
{
//Advance the reader if we are not looking at the first dataset
if (datasetNdx != 0)
aDbReader.NextResult();
//Get the property we are going to be updating based on the type of the class we will be filling
PropertyInfo propertyInfo = typeof (T).GetProperties().Single(p => p.PropertyType == aContainedDataSetReturnedTypes[datasetNdx]);
//Now get the object context to deserialize what is in the resultset into our type
var valueForProperty = aObjectContext.Translate <aContainedDataSetReturnedTypes[datasetNdx]> (aDbReader);
//Finally we update the property with the type safe information
propertyInfo.SetValue(result, valueForProperty, null);
}
return result;
}
}
但是目前我无法进行编译。
错误2运营商&#39;&lt;&#39;不能应用于类型&#39;方法的操作数 组&#39;和&#39; System.Type&#39;
有人可以帮忙吗?最终它与我们如何使用反射和传入aContainedDataSetReturnedTypes有关。只要仍然很容易调用MultiResultsetsHelper.Process&lt;&gt;()
,我很乐意改变现状。答案 0 :(得分:0)
此代码:
aObjectContext.Translate<aContainedDataSetReturnedTypes[datasetNdx]>
不起作用,因为泛型类型参数总是在编译时解析。您无法在运行时传递Type
实例。
您仍然可以调用泛型方法,但您必须use reflection。
答案 1 :(得分:0)
在上述所有方面的帮助下,我想出了以下内容(仍有待改进):
public static class MultiResultsetsHelper
{
/// <summary>
/// Given a data reader that contains multiple result sets, use the supplied object context to serialise the
/// rows of data in the result set into our property.
/// </summary>
/// <typeparam name="T">Type of the containing object that contains all the various result sets.</typeparam>
/// <param name="aDbReader">Database reader that contains all the result sets returned from the database.</param>
/// <param name="aDbContext">Data context associated with the data reader.</param>
/// <param name="aDataSetTypes">Type for each type to use when we call Translate() on the current result in the data reader.</param>
/// <param name="aContainedDataSetReturnedTypes">
/// List of types in order of which the result sets are contained within the
/// data reader. We will serilize sequentially each result set the data reader contains
/// </param>
/// <returns>Retuns an object representing all the result sets returned by the data reader.</returns>
public static T Process<T>(DbDataReader aDbReader, DbContext aDbContext, List<Type> aDataSetTypes, List<Type> aContainedDataSetReturnedTypes) where T : new()
{
//What we will be returning
T result = new T();
// Drop down to the wrapped `ObjectContext` to get access to the `Translate` method
ObjectContext objectContext = ((IObjectContextAdapter) aDbContext).ObjectContext;
//Iterate the passed in dataset types as they are in the same order as what the reader contains
for (int datasetNdx = 0; datasetNdx < aContainedDataSetReturnedTypes.Count; datasetNdx++)
{
//Advance the reader if we are not looking at the first dataset
if (datasetNdx != 0)
aDbReader.NextResult();
//Get the property we are going to be updating based on the type of the class we will be filling
PropertyInfo propertyInfo = typeof (T).GetProperties().Single(p => p.PropertyType == aContainedDataSetReturnedTypes[datasetNdx]);
//Now get the object context to deserialize what is in the resultset into our type
MethodInfo method = GetTranslateOverload(typeof (ObjectContext));
MethodInfo generic = method.MakeGenericMethod(aDataSetTypes[datasetNdx]);
//Invoke the generic method which we hvae constructed for Translate
object valueForProperty = generic.Invoke(objectContext, new object[] {aDbReader});
//Finally we update the property with the type safe information
propertyInfo.SetValue(result, valueForProperty);
}
return result;
}
/// <summary>
/// Internal helper method to get the necessary translate overload we need:
/// ObjectContext.Translate<T>(DbReader)
/// </summary>
/// <param name="aType">ObjectContext.GetType()</param>
/// <returns>Returns the method we require, null on error.</returns>
private static MethodInfo GetTranslateOverload(Type aType)
{
MethodInfo myMethod = aType
.GetMethods()
.Where(m => m.Name == "Translate")
.Select(m => new
{
Method = m,
Params = m.GetParameters(),
Args = m.GetGenericArguments()
})
.Where(x => x.Params.Length == 1
&& x.Args.Length == 1
&& x.Params[0].ParameterType == typeof (DbDataReader)
// && x.Params[0].ParameterType == x.Args[0]
)
.Select(x => x.Method)
.First();
return myMethod;
}
}
假设你有:
public class UspGetSideBarListReturnDto
{
public List<Set1ReturnDto> Dummy1 { get; set; }
public List<Set2ReturnDto> Dummy2 { get; set; }
}
public class Set1ReturnDto
{
public Int32 CruiseCount { get; set; }
public string DisplayText { get; set; }
public Int64 DisplayValue { get; set; }
}
public class Set2ReturnDto
{
public string DepartingFrom { get; set; }
public string Port_Code { get; set; }
}
您可以将其命名为:
DbDataReader reader = dbCommand.ExecuteReader();
return MultiResultsHelper.Process<UspGetSideBarListReturnDto>(reader, myDbContext, new List<Type>{typeof(Set1ReturnDto), typeof(Set2ReturnDto)}, new List<Type>{typeof(List<Set1ReturnDto>), typeof(List<Set2ReturnDto>});
aDataSetTypes的顺序需要与aDbReader中的结果集列表相对应。
改进将是: