关于存储过程:ASP.NET核心实体框架SQL查询SELECT

ASP.NET Core Entity Framework SQL Query SELECT

我是从ASP.NET到ASP.NET Core进行"升级"的众多努力之一。

在ASP.NET项目中,我像这样从DAL进行数据库调用:

1
2
3
4
5
var result = context.Database.SqlQuery<Object_VM>("EXEC [sp_Object_GetByKey] @Key",
      new SqlParameter("@Key", Key))
      .FirstOrDefault();

return result;

我的视图模型具有我的对象没有的其他字段,例如相关表的集合。在数据库/表结构中包含此类字段似乎是不必要的,而且非常直观。我的存储过程将计算所有这些内容并返回应显示但不存储的字段。

我看到ASP.NET Core删除了此功能。我试图继续使用存储过程和加载视图模型(因此在数据库中没有实体)。我看到类似以下的选项,但结果是得到" 2 ",即返回的行数(或另一个神秘的结果?)。

1
2
3
4
5
using(context)
{
    string cmd ="EXEC [sp_Object_getAll]";
    var result = context.Database.ExecuteSQLCommand(cmd);
}

但这不会起作用,因为context.Database.ExecuteSQLCommand仅用于更改数据库,而不用于" selecting "。

我也已经将以下内容视为解决方案,但是代码不会为我编译,因为" set "实际上是set<TEntity>,并且该视图模型没有数据库实体。 >

1
var result = context.Set().FromSql("EXEC [sp_Object_getAll]");

非常感谢任何帮助。


解决方案:

(按照曾梵志的建议)

在GitHub Entity Framework Issues页面上,有关于此问题的讨论。一个用户建议创建自己的类来处理此类请求,另一个用户建议添加其他方法以使其运行更加流畅。我更改了方法参数以接受稍有不同的参数。

这是我的适应内容(差异很小),对于其他也在寻找解决方案的人:

DAL中的方法

1
2
3
4
5
6
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);
}

其他课程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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
    }