![](/img/trans.png)
[英]Mapping multiple result sets stored procedure in EF 5 or EF 6 CodeFirst
[英]Generic approach to dealing with multiple result sets from EF stored procedure
我正在尝试构建一个通用的帮助程序类,该类将帮助我将每个结果集“转换”为类型安全的类,如下所述: 使用SqlQuery处理来自存储过程的多个结果
对于我的解决方案,我想将以下内容传递给我的助手类(MultiResultsetsHelper):
然后让helper类进行繁重的填充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运算符“ <”不能应用于类型“方法组”和“系统类型”的操作数
有人可以帮忙吗? 最终,它与我们如何使用反射以及如何在aContainedDataSetReturnedTypes中传递有关。 只要可以轻松调用MultiResultsetsHelper.Process <>(),我很乐意更改周围的事物
这段代码:
aObjectContext.Translate<aContainedDataSetReturnedTypes[datasetNdx]>
将不起作用,因为泛型类型参数始终在编译时解析。 您无法在运行时传递Type
实例。
您仍然可以调用通用方法,但必须使用Reflection 。
在以上所有步骤的帮助下,我提出了以下建议(仍可以改进):
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中的结果集列表相对应。
改进将是:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.