Stored procedures asp.net mvc:.net核心:如何将存储的过程结果集映射到类字段
我得到了一个简单的模型类: 公共类PrvProduct { 我正在尝试使用.net core调用一个存储的proc,它工作正常,返回一个PrvProduct对象列表。问题是:除非我自己用代码填充它们,否则它们的字段是空的。ProductId总是在那里,不知道为什么(可能是因为我在那里键入了[key]属性?) 是否有一种简单的方法可以将类字段映射到结果集,如在ado.net中(我只需要执行SQLDataAdapter.Fill(MyDataTable),MyDataTable字段将按字段名具有值)…还是每次都必须执行下面的选项2 非常感谢 字符串sqlQuery=“EXEC Maint.GetProductList”“+sNameFilter+”; //选项1:这在每个PRVPProduct的字段中不获取值(ProductId获取值可能是因为其[key],其他的则不获取) IQueryable results=_context.Products.FromSql(sqlQuery.AsNoTracking()Stored procedures asp.net mvc:.net核心:如何将存储的过程结果集映射到类字段,stored-procedures,asp.net-core,Stored Procedures,Asp.net Core,我得到了一个简单的模型类: 公共类PrvProduct { 我正在尝试使用.net core调用一个存储的proc,它工作正常,返回一个PrvProduct对象列表。问题是:除非我自己用代码填充它们,否则它们的字段是空的。ProductId总是在那里,不知道为什么(可能是因为我在那里键入了[key]属性?) 是否有一种简单的方法可以将类字段映射到结果集,如在ado.net中(我只需要执行SQLDataAdapter.Fill(MyDataTable),MyDataTable字段将按字段名具有值)
//选项2:这是可行的,但是……我是否必须对调用的每个存储过程、每个字段都这样做,或者是否有更好的方法将类字段映射到返回的结果字段?
List oList=新列表();
使用(var命令=_context.Database.GetDbConnection().CreateCommand())
{
command.CommandText=sqlQuery;
command.CommandType=CommandType.Text;
_context.Database.OpenConnection();
使用(var result=command.ExecuteReader())
{
while(result.Read())
{
//映射到您的实体
oList.Add(新PRV产品)
{
ProductId=result.GetInt32(0),
ProductName=result.GetString(1)
});
}
}
}
在EF Core中,如果您使用一个数据库集实体执行存储过程,它将自动映射。问题是,在许多情况下,您需要将存储过程映射到DTO,例如,DTO不是数据库集实体的一部分。在这些情况下,您需要返回时间并手动映射,这是浪费时间的e
为了避免手动映射数据读取器,我添加了一系列扩展方法来为您进行映射。代码并不完美,我仍在改进,但在大多数情况下已经足够好了
一旦添加了我将在下面描述的扩展方法,您就可以这样使用它:
return dbContext.Database.SqlQuery<SalesReportDTO>("spGetSalesReport",
SqlParameterBuilder.Build("customerId", customerId),
SqlParameterBuilder.Build("dateFrom", from),
SqlParameterBuilder.Build("dateTo", to)).ToList();
\u context.Products.FromSql(sqlQuery)
应该完全按照您想要的方式工作。如果不是这样,那么就有一些问题是您在这里单独提供的内容看不出来的。我的最佳猜测是您遇到了映射问题。要使FromSql
在您的上下文中映射到实体类型,列类型必须与您的类中的类型匹配。我开始t it!属性必须有get\set才能工作。我更改了类定义,它工作了:公共类prvpproduct{[Key]public Int32 ProductId{get;set;}public Int32 ProductLineId{get;set;}public String MfgPartNumber{get;set;}公共字符串产品名称{get;set;}公共字符串产品描述{get;set;}
//option 2: this works, but... do i have to do this for every stored proc i call, every field, or is there a beter way to map class fields to returned results fields?
List<PrvProduct> oList = new List<PrvProduct>();
using (var command = _context.Database.GetDbConnection().CreateCommand())
{
command.CommandText = sqlQuery;
command.CommandType = CommandType.Text;
_context.Database.OpenConnection();
using (var result = command.ExecuteReader())
{
while (result.Read())
{
// Map to your entity
oList.Add(new PrvProduct
{
ProductId = result.GetInt32(0),
ProductName = result.GetString(1)
});
}
}
}
return dbContext.Database.SqlQuery<SalesReportDTO>("spGetSalesReport",
SqlParameterBuilder.Build("customerId", customerId),
SqlParameterBuilder.Build("dateFrom", from),
SqlParameterBuilder.Build("dateTo", to)).ToList();
public static class DatabaseFacadeExtensions
{
public static List<T> SqlQuery<T>(this DatabaseFacade database, string query, params SqlParameter[] parameters)
{
return SqlQuery<T>(database, query, null, CommandType.StoredProcedure, parameters);
}
public static List<T> SqlQuery<T>(this DatabaseFacade database, string query, CommandType commandType, params SqlParameter[] parameters)
{
return SqlQuery<T>(database, query, null, commandType, parameters);
}
public static List<T> SqlQuery<T>(this DatabaseFacade database, string query, int? commandTimeout, params SqlParameter[] parameters)
{
return SqlQuery<T>(database, query, commandTimeout, CommandType.StoredProcedure, parameters);
}
public static List<T> SqlQuery<T>(this DatabaseFacade database, string query, int? commandTimeout, CommandType commandType, params SqlParameter[] parameters)
{
using (var cmd = database.GetDbConnection().CreateCommand())
{
cmd.CommandText = query;
cmd.CommandType = commandType;
if (commandTimeout.HasValue)
{
cmd.CommandTimeout = commandTimeout.Value;
}
cmd.Parameters.AddRange(parameters);
if (cmd.Connection.State == System.Data.ConnectionState.Closed)
{
cmd.Connection.Open();
}
try
{
using (var reader = cmd.ExecuteReader())
{
return reader.MapToList<T>();
}
}
finally
{
cmd.Connection.Close();
}
}
}
}
public static class DbDataReaderExtensions
{
public static List<T> MapToList<T>(this DbDataReader dr)
{
var objList = new List<T>();
if (dr.HasRows)
{
bool isSingleValue = typeof(T).IsPrimitive || typeof(T) == typeof(string);
IEnumerable<PropertyInfo> props = null;
Dictionary<string, DbColumn> colMapping = null;
if (!isSingleValue)
{
props = typeof(T).GetRuntimeProperties();
colMapping = dr.GetColumnSchema()
.Where(x => props.Any(y => y.Name.ToLower() == x.ColumnName.ToLower()))
.ToDictionary(key => key.ColumnName.ToLower());
}
while (dr.Read())
{
T obj;
if (isSingleValue)
{
obj = (T)dr.GetValue(0);
}
else
{
obj = Activator.CreateInstance<T>();
foreach (var prop in props)
{
string propertyName = prop.Name.ToLower();
if (!colMapping.ContainsKey(propertyName))
{
continue;
}
var val = dr.GetValue(colMapping[propertyName].ColumnOrdinal.Value);
if (val != DBNull.Value)
{
// enum property
if (prop.PropertyType.IsEnum)
{
prop.SetValue(obj, Enum.ToObject(prop.PropertyType, val));
}
// nullable enum property
if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) && Nullable.GetUnderlyingType(prop.PropertyType).IsEnum)
{
prop.SetValue(obj, Enum.ToObject(Nullable.GetUnderlyingType(prop.PropertyType), val));
}
else
{
prop.SetValue(obj, val);
}
}
}
}
objList.Add(obj);
}
}
return objList;
}
public static T MapToObject<T>(this DbDataReader dr)
{
var props = typeof(T).GetRuntimeProperties();
if (dr.HasRows)
{
var colMapping = dr.GetColumnSchema()
.Where(x => props.Any(y => y.Name.ToLower() == x.ColumnName.ToLower()))
.ToDictionary(key => key.ColumnName.ToLower());
if (dr.Read())
{
T obj = Activator.CreateInstance<T>();
foreach (var prop in props)
{
var val = dr.GetValue(colMapping[prop.Name.ToLower()].ColumnOrdinal.Value);
prop.SetValue(obj, val == DBNull.Value ? null : val);
}
return obj;
}
}
return default(T);
}
}
public class SqlParameterBuilder
{
public static SqlParameter Build(string name, bool? value)
{
if (value.HasValue)
{
return new SqlParameter() { ParameterName = name, Value = value.Value };
}
return new SqlParameter() { ParameterName = name, Value = DBNull.Value };
}
public static SqlParameter Build(string name, int? value)
{
if (value.HasValue)
{
return new SqlParameter() { ParameterName = name, Value = value.Value };
}
return new SqlParameter() { ParameterName = name, Value = DBNull.Value };
}
public static SqlParameter Build(string name, string value)
{
if (value != null)
{
return new SqlParameter() { ParameterName = name, Value = value };
}
return new SqlParameter() { ParameterName = name, Value = DBNull.Value };
}
public static SqlParameter Build(string name, DateTime? value)
{
if (value != null)
{
return new SqlParameter { ParameterName = name, SqlDbType = SqlDbType.DateTime, Value = value };
}
return new SqlParameter() { ParameterName = name, Value = DBNull.Value };
}
public static SqlParameter Build(string name, Guid? value)
{
if (value.HasValue)
{
return new SqlParameter { ParameterName = name, SqlDbType = SqlDbType.UniqueIdentifier, Value = value };
}
return new SqlParameter() { ParameterName = name, Value = DBNull.Value };
}
public static SqlParameter Build(string name, int[] values)
{
SqlParameter par = new SqlParameter(name, SqlDbType.Structured);
par.TypeName = "dbo.IntParameterList";
DataTable dt = new DataTable();
dt.Columns.Add("id", typeof(int));
par.Value = dt;
if (values != null)
{
foreach (int value in values.Where(p => p != 0))
{
dt.Rows.Add(value);
}
}
return par;
}
public static SqlParameter Build(string name, string[] values, VarcharParameterListEnum varcharParameterListType = VarcharParameterListEnum.Varchar50)
{
SqlParameter par = new SqlParameter(name, SqlDbType.Structured);
switch(varcharParameterListType)
{
case VarcharParameterListEnum.Varchar15:
par.TypeName = "dbo.Varchar15ParameterList";
break;
case VarcharParameterListEnum.Varchar50:
par.TypeName = "dbo.Varchar50ParameterList";
break;
case VarcharParameterListEnum.Varchar100:
par.TypeName = "dbo.Varchar100ParameterList";
break;
case VarcharParameterListEnum.Varchar255:
par.TypeName = "dbo.Varchar255ParameterList";
break;
case VarcharParameterListEnum.Varchar510:
par.TypeName = "dbo.Varchar510ParameterList";
break;
}
DataTable dt = new DataTable();
dt.Columns.Add("textValue", typeof(string));
par.Value = dt;
if (values != null)
{
foreach (var value in values.Where(p => !string.IsNullOrWhiteSpace(p)))
{
dt.Rows.Add(value);
}
}
return par;
}
}