在 EF Core 3.1 中包含 FromSqlRaw 和存储过程

Gle*_*leb 17 .net c# entity-framework join entity-framework-core

所以这是交易 - 我目前正在使用 EF Core 3.1,假设我有一个实体:

public class Entity
{
    public int Id { get; set; }
    public int AnotherEntityId { get; set; }
    public virtual AnotherEntity AnotherEntity { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

当我以DbSet<Entity> Entities正常方式访问时,我包括另一个实体,如:

_context.Entities.Include(e => e.AnotherEntity)

这有效。为什么不会,对吧?然后我去:

_context.Entities.FromSqlRaw("SELECT * FROM Entities").Include(e => e.AnotherEntity)

这也有效。两者都返回与另一个实体连接的相同对象集合。然后我使用一个存储过程,它由SELECT * FROM Entities名为 spGetEntities的相同查询组成:

_context.Entities.FromSqlRaw("spGetEntities")

你猜怎么着?这也有效。它给了我相同的输出,但显然没有加入另一个实体。但是,如果我尝试像这样添加 Include:

_context.Entities.FromSqlRaw("spGetEntities").Include(e => e.AnotherEntity)

我正进入(状态:

FromSqlRaw 或 FromSqlInterpolated 是用不可组合的 SQL 调用的,并且查询在它上面组合。考虑AsEnumerable 在 FromSqlRaw 或 FromSqlInterpolated 方法之后调用以在客户端执行组合。

即使_context.Entities.FromSqlRaw("SELECT * FROM Entities")和的输出_context.Entities.FromSqlRaw("spGetEntities") 相同。

我找不到证明我可以或不能使用 EF Core 3.1 做到这一点的证据,但如果有人能给我任何这种方法的可能性的暗示,那就太好了。

另外,如果有另一种方法可以使用存储过程来获得加入的实体,我可能会接受它作为我的问题的解决方案。

Iva*_*oev 12

很快,您不能这样做(至少对于 SqlServer)。解释包含在 EF Core 文档 - Raw SQL Queries - Composing with LINQ 中

使用 LINQ 进行组合要求原始 SQL 查询是可组合的,因为 EF Core 会将提供的 SQL 视为子查询。可以以SELECT关键字开头的 SQL 查询。此外,传递的 SQL 不应包含任何对子查询无效的字符或选项,例如:

  • 尾随分号
  • 在 SQL Server 上,尾随查询级提示(例如,OPTION (HASH JOIN)
  • 在 SQL Server 上,ORDER BY子句中未使用OFFSET 0 OR TOP 100 PERCENTSELECT子句

SQL Server 不允许组合存储过程调用,因此任何将附加查询运算符应用于此类调用的尝试都将导致 SQL 无效。立即使用AsEnumerableAsAsyncEnumerable方法FromSqlRawFromSqlInterpolated方法以确保 EF Core 不会尝试组合存储过程。

此外,由于Include/ ThenIncluderequire EF Core IQueryable<>AsEnumerable/AsAsyncEnumerable等不是一个选项。您确实需要可组合的 SQL,因此没有选择存储过程。

不过,您可以使用表值函数 (TVF) 或数据库视图代替存储过程,因为它们是可组合的(select * from TVF(params)select * from db_view)。