Asp.net mvc MVC 5实体框架6执行存储过程
我卡住了。我有一个现有的应用程序,它有一个非常大的数据库和大量的存储过程和函数库。我所要做的就是使用DbContext执行存储过程,并返回一组数据或映射到上下文中的一个实体。这是我在网上没有发现的神奇的东西吗?任何人,任何人,请帮忙。以下是我到目前为止得到的结果(它没有返回任何结果,结果是-1): 执行返回-1的。我也尝试了一些类似的方法,但没有成功:Asp.net mvc MVC 5实体框架6执行存储过程,asp.net-mvc,stored-procedures,entity-framework-6,Asp.net Mvc,Stored Procedures,Entity Framework 6,我卡住了。我有一个现有的应用程序,它有一个非常大的数据库和大量的存储过程和函数库。我所要做的就是使用DbContext执行存储过程,并返回一组数据或映射到上下文中的一个实体。这是我在网上没有发现的神奇的东西吗?任何人,任何人,请帮忙。以下是我到目前为止得到的结果(它没有返回任何结果,结果是-1): 执行返回-1的。我也尝试了一些类似的方法,但没有成功: DbRawSqlQuery<Contact> data = db.Database.SqlQuery<Contact>
DbRawSqlQuery<Contact> data = db.Database.SqlQuery<Contact>
("EXEC Contact_Search @LastName, @FirstName",
GetDataValue(args.LastName),
GetDataValue(args.FirstName));
DbRawSqlQuery data=db.Database.SqlQuery
(“执行联系人搜索@LastName,@FirstName”,
GetDataValue(args.LastName),
GetDataValue(args.FirstName));
我知道我可以通过这种方式将edmx和映射添加到存储过程中,但这不是首选方法。同样,我们的数据库包含近4.5亿条记录和一个包含近3000个存储过程和函数的库。这将是一场噩梦。我开始的方向对吗?实体框架是正确的选择吗 哇,似乎就在我放弃之后,我不知怎的找到了答案。我找到了一个关于执行存储过程的解决方案,在阅读之后,这是我的解决方案:
var contacts = db.Database.SqlQuery<Contact>("Contact_Search @LastName, @FirstName",
var contacts=db.Database.SqlQuery(“Contact_Search@LastName,@FirstName”,
因此,非常感谢Anuraj的出色文章!我的解决方案的关键是首先使用
SqlQuery
而不是ExecuteSqlCommand
,并执行到我的实体模型(Contact
)的方法映射。此代码比SqlQuery()好,因为SqlQuery()不识别[Column]属性。
这是一个银盘
public static class StoredProcedureExtensions {
/// <summary>
/// Execute Stored Procedure and return result in an enumerable object.
/// </summary>
/// <typeparam name="TEntity">Type of enumerable object class to return.</typeparam>
/// <param name="commandText">SQL query.</param>
/// <param name="parameters">SQL parameters.</param>
/// <param name="readOnly">Determines whether to attach and track changes for saving. Defaults to true and entities will not be tracked and thus a faster call.</param>
/// <returns>IEnumerable of entity type.</returns>
public static IEnumerable<TEntity> GetStoredProcedureResults<TEntity>(this DbContext dbContext, string query, Dictionary<string, object> parameters, bool readOnly = true) where TEntity : class, new()
{
SqlParameter[] sqlParameterArray = DbContextExtensions.DictionaryToSqlParameters(parameters);
return dbContext.GetStoredProcedureResults<TEntity>(query, sqlParameterArray, readOnly);
}
/// <summary>
/// Execute Stored Procedure and return result in an enumerable object.
/// </summary>
/// <typeparam name="TEntity">Type of enumerable object class to return.</typeparam>
/// <param name="commandText">SQL query.</param>
/// <param name="parameters">SQL parameters.</param>
/// <param name="readOnly">Determines whether to attach and track changes for saving. Defaults to true and entities will not be tracked and thus a faster call.</param>
/// <returns>IEnumerable of entity type.</returns>
public static IEnumerable<TEntity> GetStoredProcedureResults<TEntity>(this DbContext dbContext, string commandText, SqlParameter[] sqlParameterArray = null, bool readOnly = true) where TEntity : class, new()
{
string infoMsg = commandText;
try
{
//---- For a better error message
if (sqlParameterArray != null)
{
foreach (SqlParameter p in sqlParameterArray)
{
infoMsg += string.Format(" {0}={1}, ", p.ParameterName, p.Value == null ? "(null)" : p.Value.ToString());
}
infoMsg = infoMsg.Trim().TrimEnd(',');
}
///////////////////////////
var reader = GetReader(dbContext, commandText, sqlParameterArray, CommandType.StoredProcedure);
///////////////////////////
///////////////////////////
List<TEntity> results = GetListFromDataReader<TEntity>(reader);
///////////////////////////
if(readOnly == false)
{
DbSet entitySet = dbContext.Set<TEntity>(); // For attaching the entities so EF can track changes
results.ForEach(n => entitySet.Attach(n)); // Add tracking to each entity
}
reader.Close();
return results.AsEnumerable();
}
catch (Exception ex)
{
throw new Exception("An error occurred while executing GetStoredProcedureResults(). " + infoMsg + ". Check the inner exception for more details.\r\n" + ex.Message, ex);
}
}
//========================================= Private methods
#region Private Methods
private static DbDataReader GetReader(DbContext dbContext, string commandText, SqlParameter[] sqlParameterArray, CommandType commandType)
{
var command = dbContext.Database.Connection.CreateCommand();
command.CommandText = commandText;
command.CommandType = commandType;
if (sqlParameterArray != null) command.Parameters.AddRange(sqlParameterArray);
dbContext.Database.Connection.Open();
var reader = command.ExecuteReader(CommandBehavior.CloseConnection);
return reader;
}
private static List<TEntity> GetListFromDataReader<TEntity>(DbDataReader reader) where TEntity : class, new()
{
PropertyInfo[] entityProperties = typeof(TEntity).GetProperties();
IEnumerable<string> readerColumnNames = (reader.GetSchemaTable().Select()).Select(r => r.ItemArray[0].ToString().ToUpper()); // uppercase reader column names.
List<MappingPropertyToColumn> propertyToColumnMappings = GetPropertyToColumnMappings<TEntity>(); // Maps the entity property names to the corresponding names of the columns in the reader
var entityList = new List<TEntity>(); // Fill this
while (reader.Read())
{
var element = Activator.CreateInstance<TEntity>();
foreach (var entityProperty in entityProperties)
{
MappingPropertyToColumn mapping = propertyToColumnMappings._Find(entityProperty.Name);
if (mapping == null) // This property has a [Not Mapped] attribute
{
continue; // Skip this one
}
var o = (object)reader[mapping.ColumnName]; // mapping must match all mapped properties to columns. If result set does not contain a column, then throw error like EF would.
bool hasValue = o.GetType() != typeof(DBNull);
if (mapping.IsEnum && hasValue) // Enum
{
entityProperty.SetValue(element, Enum.Parse(mapping.UnderlyingType, o.ToString()));
}
else
{
if (hasValue)
{
entityProperty.SetValue(element, ChangeType(o, entityProperty.PropertyType));
}
}
}
entityList.Add(element);
}
return entityList;
}
public static object ChangeType(object value, Type conversion)
{
var t = conversion;
if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
if (value == null)
{
return null;
}
t = Nullable.GetUnderlyingType(t);
}
return Convert.ChangeType(value, t);
}
private static List<MappingPropertyToColumn> GetPropertyToColumnMappings<TEntity>() where TEntity : new()
{
var type = typeof(TEntity);
List<MappingPropertyToColumn> databaseMappings = new List<MappingPropertyToColumn>();
foreach (var entityProperty in type.GetProperties())
{
bool isEnum = entityProperty.PropertyType.IsEnum;
// [Not Mapped] Not Mapped Attribute
var notMapped = entityProperty.GetCustomAttributes(false).FirstOrDefault(attribute => attribute is NotMappedAttribute);
if (notMapped != null) // This property has a [Not Mapped] attribute
{
continue; // Skip this property
}
// Determine if property is an enum
Type underlyingType = null;
if (entityProperty.PropertyType.IsGenericType && entityProperty.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
underlyingType = Nullable.GetUnderlyingType(entityProperty.PropertyType); ;
if (underlyingType != null && underlyingType.IsEnum)
{
isEnum = true;
}
}
// [Column("tbl_columnname")] Column Name Attribute for mapping
var columnMapping = entityProperty.GetCustomAttributes(false).FirstOrDefault(attribute => attribute is ColumnAttribute);
if (columnMapping != null)
{
databaseMappings.Add(new MappingPropertyToColumn { PropertyName = entityProperty.Name, ColumnName = ((ColumnAttribute)columnMapping).Name.ToUpper(), IsEnum = isEnum, UnderlyingType = underlyingType }); // SQL case insensitive
}
else
{
databaseMappings._AddProperty(entityProperty.Name, entityProperty.Name, isEnum); // C# case sensitive
}
}
return databaseMappings;
}
//====================================== Class for holding column mappings and other info for each property
private class MappingPropertyToColumn
{
private string _propertyName;
public string PropertyName
{
get { return _propertyName; }
set { _propertyName = value; }
}
private string _columnName;
public string ColumnName
{
get { return _columnName; }
set { _columnName = value; }
}
private bool _isNullableEnum;
public bool IsEnum
{
get { return _isNullableEnum; }
set { _isNullableEnum = value; }
}
private Type _underlyingType;
public Type UnderlyingType
{
get { return _underlyingType; }
set { _underlyingType = value; }
}
}
//======================================================= List<MappingPropertyToColumn> Extension methods
#region List<MappingPropertyToColumn> Extension methods
private static bool _ContainsKey<T>(this List<T> list, string key) where T : MappingPropertyToColumn
{
return list.Any(x => x.PropertyName == key);
}
private static MappingPropertyToColumn _Find<T>(this List<T> list, string key) where T : MappingPropertyToColumn
{
return list.Where(x => x.PropertyName == key).FirstOrDefault();
}
private static void _AddProperty<T>(this List<T> list, string propertyName, string columnName, bool isEnum, Type underlyingType = null) where T : MappingPropertyToColumn
{
list.Add((T)new MappingPropertyToColumn { PropertyName = propertyName, ColumnName = columnName, IsEnum = isEnum, UnderlyingType = underlyingType }); // C# case sensitive
}
#endregion
#endregion }
公共静态类StoredProcedureExtensions{
///
///执行存储过程并在可枚举对象中返回结果。
///
///要返回的可枚举对象类的类型。
///SQL查询。
///SQL参数。
///确定是否附加和跟踪更改以进行保存。默认值为true,将不跟踪实体,因此调用速度更快。
///实体类型的IEnumerable。
公共静态IEnumerable GetStoredProcedureResults(此DbContext DbContext,字符串查询,字典参数,bool readOnly=true),其中TEntity:class,new()
{
SqlParameter[]sqlParameterArray=DbContextExtensions.DictionaryToSqlParameters(参数);
返回dbContext.GetStoredProcedureResults(查询,sqlParameterArray,只读);
}
///
///执行存储过程并在可枚举对象中返回结果。
///
///要返回的可枚举对象类的类型。
///SQL查询。
///SQL参数。
///确定是否附加和跟踪更改以进行保存。默认值为true,将不跟踪实体,因此调用速度更快。
///实体类型的IEnumerable。
公共静态IEnumerable GetStoredProcedureResults(此DbContext DbContext,string commandText,SqlParameter[]sqlParameterArray=null,bool readOnly=true),其中tenty:class,new()
{
字符串infoMsg=commandText;
尝试
{
//----获取更好的错误消息
if(sqlParameterArray!=null)
{
foreach(sqlParameterArray中的SQLP参数)
{
infoMsg+=string.Format(“{0}={1}”,p.ParameterName,p.Value==null?”(null)”:p.Value.ToString();
}
infoMsg=infoMsg.Trim().TrimEnd(',');
}
///////////////////////////
var reader=GetReader(dbContext、commandText、sqlParameterArray、CommandType.StoredProcess);
///////////////////////////
///////////////////////////
列表结果=GetListFromDataReader(reader);
///////////////////////////
如果(只读==false)
{
DbSet entitySet=dbContext.Set();//用于附加实体,以便EF可以跟踪更改
results.ForEach(n=>entitySet.Attach(n));//为每个实体添加跟踪
}
reader.Close();
返回结果;
}
捕获(例外情况除外)
{
抛出新异常(“执行GetStoredProcedureResults()时出错。“+infoMsg+”。有关详细信息,请检查内部异常。\r\n“+ex.Message,ex”);
}
}
//===================================================================专用方法
#区域私有方法
私有静态DbDataReader GetReader(DbContext DbContext,string commandText,SqlParameter[]sqlParameterArray,CommandType CommandType)
{
var command=dbContext.Database.Connection.CreateCommand();
command.CommandText=CommandText;
command.CommandType=CommandType;
if(sqlParameterArray!=null)命令.Parameters.AddRange(sqlParameterArray);
dbContext.Database.Connection.Open();
var reader=command.ExecuteReader(CommandBehavior.CloseConnection);
返回读取器;
}
私有静态列表GetListFromDataReader(DbDataReader reader),其中tenty:class,new()
{
PropertyInfo[]entityProperties=typeof(tenty).GetProperties();
IEnumerable readerColumnNames=(reader.GetSchemaTable().Select()).Select(r=>r.ItemArray[0].ToString().ToUpper());//大写的阅读器列名。
List propertyToColumnMappings=GetPropertyToColumnMappings();//将实体属性名称映射到读取器中相应列的名称
var entityList=new List();//填写此
while(reader.Read())
{
var element=Activator.CreateInstance();
foreach(entityProperty中的var entityProperty)
{
MappingPropertyToColumnMapping=propertyToColumnMappings.\u Find(entityProperty.Name);
if(mapping==null)//此属性具有[未映射]属性
{
继续;//跳过这个
}
var o=(对象)读取器[mapping.ColumnName];//映射必须将所有映射属性匹配到列。如果结果集不包含列,则会像EF一样抛出错误。
bool hasValue=o.GetType()!=typeof(DBNull);
if(mapping.IsEnum&&hasValue)//Enu
public static class StoredProcedureExtensions {
/// <summary>
/// Execute Stored Procedure and return result in an enumerable object.
/// </summary>
/// <typeparam name="TEntity">Type of enumerable object class to return.</typeparam>
/// <param name="commandText">SQL query.</param>
/// <param name="parameters">SQL parameters.</param>
/// <param name="readOnly">Determines whether to attach and track changes for saving. Defaults to true and entities will not be tracked and thus a faster call.</param>
/// <returns>IEnumerable of entity type.</returns>
public static IEnumerable<TEntity> GetStoredProcedureResults<TEntity>(this DbContext dbContext, string query, Dictionary<string, object> parameters, bool readOnly = true) where TEntity : class, new()
{
SqlParameter[] sqlParameterArray = DbContextExtensions.DictionaryToSqlParameters(parameters);
return dbContext.GetStoredProcedureResults<TEntity>(query, sqlParameterArray, readOnly);
}
/// <summary>
/// Execute Stored Procedure and return result in an enumerable object.
/// </summary>
/// <typeparam name="TEntity">Type of enumerable object class to return.</typeparam>
/// <param name="commandText">SQL query.</param>
/// <param name="parameters">SQL parameters.</param>
/// <param name="readOnly">Determines whether to attach and track changes for saving. Defaults to true and entities will not be tracked and thus a faster call.</param>
/// <returns>IEnumerable of entity type.</returns>
public static IEnumerable<TEntity> GetStoredProcedureResults<TEntity>(this DbContext dbContext, string commandText, SqlParameter[] sqlParameterArray = null, bool readOnly = true) where TEntity : class, new()
{
string infoMsg = commandText;
try
{
//---- For a better error message
if (sqlParameterArray != null)
{
foreach (SqlParameter p in sqlParameterArray)
{
infoMsg += string.Format(" {0}={1}, ", p.ParameterName, p.Value == null ? "(null)" : p.Value.ToString());
}
infoMsg = infoMsg.Trim().TrimEnd(',');
}
///////////////////////////
var reader = GetReader(dbContext, commandText, sqlParameterArray, CommandType.StoredProcedure);
///////////////////////////
///////////////////////////
List<TEntity> results = GetListFromDataReader<TEntity>(reader);
///////////////////////////
if(readOnly == false)
{
DbSet entitySet = dbContext.Set<TEntity>(); // For attaching the entities so EF can track changes
results.ForEach(n => entitySet.Attach(n)); // Add tracking to each entity
}
reader.Close();
return results.AsEnumerable();
}
catch (Exception ex)
{
throw new Exception("An error occurred while executing GetStoredProcedureResults(). " + infoMsg + ". Check the inner exception for more details.\r\n" + ex.Message, ex);
}
}
//========================================= Private methods
#region Private Methods
private static DbDataReader GetReader(DbContext dbContext, string commandText, SqlParameter[] sqlParameterArray, CommandType commandType)
{
var command = dbContext.Database.Connection.CreateCommand();
command.CommandText = commandText;
command.CommandType = commandType;
if (sqlParameterArray != null) command.Parameters.AddRange(sqlParameterArray);
dbContext.Database.Connection.Open();
var reader = command.ExecuteReader(CommandBehavior.CloseConnection);
return reader;
}
private static List<TEntity> GetListFromDataReader<TEntity>(DbDataReader reader) where TEntity : class, new()
{
PropertyInfo[] entityProperties = typeof(TEntity).GetProperties();
IEnumerable<string> readerColumnNames = (reader.GetSchemaTable().Select()).Select(r => r.ItemArray[0].ToString().ToUpper()); // uppercase reader column names.
List<MappingPropertyToColumn> propertyToColumnMappings = GetPropertyToColumnMappings<TEntity>(); // Maps the entity property names to the corresponding names of the columns in the reader
var entityList = new List<TEntity>(); // Fill this
while (reader.Read())
{
var element = Activator.CreateInstance<TEntity>();
foreach (var entityProperty in entityProperties)
{
MappingPropertyToColumn mapping = propertyToColumnMappings._Find(entityProperty.Name);
if (mapping == null) // This property has a [Not Mapped] attribute
{
continue; // Skip this one
}
var o = (object)reader[mapping.ColumnName]; // mapping must match all mapped properties to columns. If result set does not contain a column, then throw error like EF would.
bool hasValue = o.GetType() != typeof(DBNull);
if (mapping.IsEnum && hasValue) // Enum
{
entityProperty.SetValue(element, Enum.Parse(mapping.UnderlyingType, o.ToString()));
}
else
{
if (hasValue)
{
entityProperty.SetValue(element, ChangeType(o, entityProperty.PropertyType));
}
}
}
entityList.Add(element);
}
return entityList;
}
public static object ChangeType(object value, Type conversion)
{
var t = conversion;
if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
if (value == null)
{
return null;
}
t = Nullable.GetUnderlyingType(t);
}
return Convert.ChangeType(value, t);
}
private static List<MappingPropertyToColumn> GetPropertyToColumnMappings<TEntity>() where TEntity : new()
{
var type = typeof(TEntity);
List<MappingPropertyToColumn> databaseMappings = new List<MappingPropertyToColumn>();
foreach (var entityProperty in type.GetProperties())
{
bool isEnum = entityProperty.PropertyType.IsEnum;
// [Not Mapped] Not Mapped Attribute
var notMapped = entityProperty.GetCustomAttributes(false).FirstOrDefault(attribute => attribute is NotMappedAttribute);
if (notMapped != null) // This property has a [Not Mapped] attribute
{
continue; // Skip this property
}
// Determine if property is an enum
Type underlyingType = null;
if (entityProperty.PropertyType.IsGenericType && entityProperty.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
underlyingType = Nullable.GetUnderlyingType(entityProperty.PropertyType); ;
if (underlyingType != null && underlyingType.IsEnum)
{
isEnum = true;
}
}
// [Column("tbl_columnname")] Column Name Attribute for mapping
var columnMapping = entityProperty.GetCustomAttributes(false).FirstOrDefault(attribute => attribute is ColumnAttribute);
if (columnMapping != null)
{
databaseMappings.Add(new MappingPropertyToColumn { PropertyName = entityProperty.Name, ColumnName = ((ColumnAttribute)columnMapping).Name.ToUpper(), IsEnum = isEnum, UnderlyingType = underlyingType }); // SQL case insensitive
}
else
{
databaseMappings._AddProperty(entityProperty.Name, entityProperty.Name, isEnum); // C# case sensitive
}
}
return databaseMappings;
}
//====================================== Class for holding column mappings and other info for each property
private class MappingPropertyToColumn
{
private string _propertyName;
public string PropertyName
{
get { return _propertyName; }
set { _propertyName = value; }
}
private string _columnName;
public string ColumnName
{
get { return _columnName; }
set { _columnName = value; }
}
private bool _isNullableEnum;
public bool IsEnum
{
get { return _isNullableEnum; }
set { _isNullableEnum = value; }
}
private Type _underlyingType;
public Type UnderlyingType
{
get { return _underlyingType; }
set { _underlyingType = value; }
}
}
//======================================================= List<MappingPropertyToColumn> Extension methods
#region List<MappingPropertyToColumn> Extension methods
private static bool _ContainsKey<T>(this List<T> list, string key) where T : MappingPropertyToColumn
{
return list.Any(x => x.PropertyName == key);
}
private static MappingPropertyToColumn _Find<T>(this List<T> list, string key) where T : MappingPropertyToColumn
{
return list.Where(x => x.PropertyName == key).FirstOrDefault();
}
private static void _AddProperty<T>(this List<T> list, string propertyName, string columnName, bool isEnum, Type underlyingType = null) where T : MappingPropertyToColumn
{
list.Add((T)new MappingPropertyToColumn { PropertyName = propertyName, ColumnName = columnName, IsEnum = isEnum, UnderlyingType = underlyingType }); // C# case sensitive
}
#endregion
#endregion }