DbContext.Set().SqlQuery 加载相关实体

本文关键字:加载 SqlQuery 实体 Set DbContext | 更新日期: 2023-09-27 18:34:18

我正在运行以下代码:

var paramUserId = new SqlParameter
{
    ParameterName = "userId",
    Value = userId
};
string query = string.Format("{0} {1}",
              "usp_GetItems",
              "@userId");
var results = _context.Set<Item>().SqlQuery(query, paramUserId);

usp_GetItems是我拥有的存储过程。但是,我的导航属性未加载。有没有办法在实体框架上完成这一点?

因为根据这个问题,在EntityFramework中使用DbContext.Database.SqlQuery进行预先加载看起来是可能的。

谢谢

DbContext.Set<T>().SqlQuery 加载相关实体

假设存储过程返回ItemsUsers的非规范化,我想到的一个想法是使用投影DTO来模拟存储过程结果的结构,然后使用SqlQueryContext.Database.SqlQuery<T>风格投影到扁平的DTO中。

然后,您可以使用 LINQ 再次将结果集重新规范化回实体图,我想这是初衷。

详细地

假设 EF 模型中的现有实体:

public class Item
{
    public int ItemId { get; set; }
    public string Name { get; set; }
}
public class User
{
    public int UserId { get; set; }
    public string Name { get; set; }
    public ICollection<Item> Items { get; set; }
}

创建一个传输 DTO,它表示存储过程结果集的扁平结构:

public class UserItemProcDto
{
    public int ItemId { get; set; }
    public string ItemName { get; set; }
    public int UserId { get; set; }
    public string UserName { get; set; }
}

然后投影到非规范化的 DTO 中,最后使用 LINQ 重新规范化:

var results = _context.SqlQuery<UserItemProcDto>(query, paramUserId);
var usersWithItems = results.GroupBy(r => r.UserId)
    .Select(g => new User
    {
        UserId = g.Key,
        Name = g.First().UserName,
        Items = g.Select(i => new Item
        {
            ItemId = i.ItemId,
            Name = i.ItemName
        }).ToList()
    });
当然,对于

跨多个表的许多存储过程,这显然不是您想要做的事情:)