ASP.NET核心Entity FrameworkSQL查询SELECT
ASP.NET Core Entity Framework SQL Query SELECT
我是众多努力 "upgrade" 从 ASP.NET 到 ASP.NET 核心的人之一。
在 ASP.NET 项目中,我像这样从 DAL 调用数据库:
var result = context.Database.SqlQuery<Object_VM>("EXEC [sp_Object_GetByKey] @Key",
new SqlParameter("@Key", Key))
.FirstOrDefault();
return result;
我的视图模型有我的对象没有的附加字段,例如相关 table 的聚合。在数据库 / table 结构中包含这些字段似乎是不必要的,而且违反直觉。我的存储过程计算所有这些东西和 returns 应显示但不存储的字段。
我看到 ASP.NET Core 已删除此功能。我试图继续使用存储过程和加载视图模型(因此数据库中没有实体)。我看到如下选项,但结果是“2”,返回的行数(或另一个神秘的结果?)。
using(context)
{
string cmd = "EXEC [sp_Object_getAll]";
var result = context.Database.ExecuteSQLCommand(cmd);
}
但这行不通,因为 context.Database.ExecuteSQLCommand
仅用于更改数据库,而不是 "selecting"。
我也看到了下面的解决方案,但是代码不会为我编译,因为 "set" 实际上是 set<TEntity>
,并且这个视图模型没有数据库实体.
var result = context.Set().FromSql("EXEC [sp_Object_getAll]");
非常感谢任何帮助。
解法:
(根据 Tseng 的建议)
在 GitHub Entity Framework Issues page, there is a discussion about this problem. One user recommends creating your own class to handle this sort of requests, and another adds an additional method 上 运行 更流畅。我改变了方法 slights 以接受略有不同的参数。
这是我的改编(差别很小),供其他也在寻找解决方案的人参考:
DAL中的方法
public JsonResult GetObjectByID(int ID)
{
SqlParameter[] parms = new SqlParameter[] { new SqlParameter("@ID", ID) };
var result = RDFacadeExtensions.GetModelFromQuery<Object_List_VM>(context, "EXEC [sp_Object_GetList] @ID", parms);
return new JsonResult(result.ToList(), setting);
}
额外Class
public static class RDFacadeExtensions
{
public static RelationalDataReader ExecuteSqlQuery(
this DatabaseFacade databaseFacade,
string sql,
SqlParameter[] parameters)
{
var concurrencyDetector = databaseFacade.GetService<IConcurrencyDetector>();
using (concurrencyDetector.EnterCriticalSection())
{
var rawSqlCommand = databaseFacade
.GetService<IRawSqlCommandBuilder>()
.Build(sql, parameters);
return rawSqlCommand
.RelationalCommand
.ExecuteReader(
databaseFacade.GetService<IRelationalConnection>(),
parameterValues: rawSqlCommand.ParameterValues);
}
}
public static IEnumerable<T> GetModelFromQuery<T>(
DbContext context,
string sql,
SqlParameter[] parameters)
where T : new()
{
DatabaseFacade databaseFacade = new DatabaseFacade(context);
using (DbDataReader dr = databaseFacade.ExecuteSqlQuery(sql, parameters).DbDataReader)
{
List<T> lst = new List<T>();
PropertyInfo[] props = typeof(T).GetProperties();
while (dr.Read())
{
T t = new T();
IEnumerable<string> actualNames = dr.GetColumnSchema().Select(o => o.ColumnName);
for (int i = 0; i < props.Length; ++i)
{
PropertyInfo pi = props[i];
if (!pi.CanWrite) continue;
System.ComponentModel.DataAnnotations.Schema.ColumnAttribute ca = pi.GetCustomAttribute(typeof(System.ComponentModel.DataAnnotations.Schema.ColumnAttribute)) as System.ComponentModel.DataAnnotations.Schema.ColumnAttribute;
string name = ca?.Name ?? pi.Name;
if (pi == null) continue;
if (!actualNames.Contains(name)) { continue; }
object value = dr[name];
Type pt = pi.DeclaringType;
bool nullable = pt.GetTypeInfo().IsGenericType && pt.GetGenericTypeDefinition() == typeof(Nullable<>);
if (value == DBNull.Value) { value = null; }
if (value == null && pt.GetTypeInfo().IsValueType && !nullable)
{ value = Activator.CreateInstance(pt); }
pi.SetValue(t, value);
}//for i
lst.Add(t);
}//while
return lst;
}//using dr
}
我是众多努力 "upgrade" 从 ASP.NET 到 ASP.NET 核心的人之一。
在 ASP.NET 项目中,我像这样从 DAL 调用数据库:
var result = context.Database.SqlQuery<Object_VM>("EXEC [sp_Object_GetByKey] @Key",
new SqlParameter("@Key", Key))
.FirstOrDefault();
return result;
我的视图模型有我的对象没有的附加字段,例如相关 table 的聚合。在数据库 / table 结构中包含这些字段似乎是不必要的,而且违反直觉。我的存储过程计算所有这些东西和 returns 应显示但不存储的字段。
我看到 ASP.NET Core 已删除此功能。我试图继续使用存储过程和加载视图模型(因此数据库中没有实体)。我看到如下选项,但结果是“2”,返回的行数(或另一个神秘的结果?)。
using(context)
{
string cmd = "EXEC [sp_Object_getAll]";
var result = context.Database.ExecuteSQLCommand(cmd);
}
但这行不通,因为 context.Database.ExecuteSQLCommand
仅用于更改数据库,而不是 "selecting"。
我也看到了下面的解决方案,但是代码不会为我编译,因为 "set" 实际上是 set<TEntity>
,并且这个视图模型没有数据库实体.
var result = context.Set().FromSql("EXEC [sp_Object_getAll]");
非常感谢任何帮助。
解法:
(根据 Tseng 的建议)
在 GitHub Entity Framework Issues page, there is a discussion about this problem. One user recommends creating your own class to handle this sort of requests, and another adds an additional method 上 运行 更流畅。我改变了方法 slights 以接受略有不同的参数。
这是我的改编(差别很小),供其他也在寻找解决方案的人参考:
DAL中的方法
public JsonResult GetObjectByID(int ID)
{
SqlParameter[] parms = new SqlParameter[] { new SqlParameter("@ID", ID) };
var result = RDFacadeExtensions.GetModelFromQuery<Object_List_VM>(context, "EXEC [sp_Object_GetList] @ID", parms);
return new JsonResult(result.ToList(), setting);
}
额外Class
public static class RDFacadeExtensions
{
public static RelationalDataReader ExecuteSqlQuery(
this DatabaseFacade databaseFacade,
string sql,
SqlParameter[] parameters)
{
var concurrencyDetector = databaseFacade.GetService<IConcurrencyDetector>();
using (concurrencyDetector.EnterCriticalSection())
{
var rawSqlCommand = databaseFacade
.GetService<IRawSqlCommandBuilder>()
.Build(sql, parameters);
return rawSqlCommand
.RelationalCommand
.ExecuteReader(
databaseFacade.GetService<IRelationalConnection>(),
parameterValues: rawSqlCommand.ParameterValues);
}
}
public static IEnumerable<T> GetModelFromQuery<T>(
DbContext context,
string sql,
SqlParameter[] parameters)
where T : new()
{
DatabaseFacade databaseFacade = new DatabaseFacade(context);
using (DbDataReader dr = databaseFacade.ExecuteSqlQuery(sql, parameters).DbDataReader)
{
List<T> lst = new List<T>();
PropertyInfo[] props = typeof(T).GetProperties();
while (dr.Read())
{
T t = new T();
IEnumerable<string> actualNames = dr.GetColumnSchema().Select(o => o.ColumnName);
for (int i = 0; i < props.Length; ++i)
{
PropertyInfo pi = props[i];
if (!pi.CanWrite) continue;
System.ComponentModel.DataAnnotations.Schema.ColumnAttribute ca = pi.GetCustomAttribute(typeof(System.ComponentModel.DataAnnotations.Schema.ColumnAttribute)) as System.ComponentModel.DataAnnotations.Schema.ColumnAttribute;
string name = ca?.Name ?? pi.Name;
if (pi == null) continue;
if (!actualNames.Contains(name)) { continue; }
object value = dr[name];
Type pt = pi.DeclaringType;
bool nullable = pt.GetTypeInfo().IsGenericType && pt.GetGenericTypeDefinition() == typeof(Nullable<>);
if (value == DBNull.Value) { value = null; }
if (value == null && pt.GetTypeInfo().IsValueType && !nullable)
{ value = Activator.CreateInstance(pt); }
pi.SetValue(t, value);
}//for i
lst.Add(t);
}//while
return lst;
}//using dr
}