繁体   English   中英

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

[英]Include with FromSqlRaw and stored procedure in EF Core 3.1

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

public class Entity
{
    public int Id { get; set; }
    public int AnotherEntityId { get; set; }
    public virtual AnotherEntity AnotherEntity { get; set; }
}

当我以正常方式访问DbSet<Entity> Entities时,我将 AnotherEntity 包括在内,例如:

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

这有效。 为什么不呢,对吧? 然后我 go 与:

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

这也有效。 两者都返回与 AnotherEntity 连接的相同对象集合。 然后我使用一个存储过程,它包含相同的查询SELECT * FROM Entities

_context.Entities.FromSqlRaw("spGetEntities")

你猜怎么了? 这也有效。 它给了我相同的 output 但显然没有加入 AnotherEntity。 但是,如果我尝试像这样添加 Include :

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

我正进入(状态:

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

即使_context.Entities.FromSqlRaw("SELECT * FROM Entities")_context.Entities.FromSqlRaw("spGetEntities")的 output 是相同的。

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

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

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

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

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

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

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

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

就我而言,我正在将带有存储过程 2.1 代码的工作 EF FromSql()转换为 3.1。 像这样:

ctx.Ledger_Accounts.FromSql("AccountSums @from, @until, @administrationId",
                                                            new SqlParameter("from", from),
                                                            new SqlParameter("until", until),
                                                            new SqlParameter("administrationId", administrationId));

其中AccountSums是 SP。

我唯一需要做的就是使用FromSqlRaw()并添加IgnoreQueryFilters()让它再次工作。 像这样:

ctx.Ledger_Accounts.FromSqlRaw("AccountSums @from, @until, @administrationId",
               new SqlParameter("from", from),
               new SqlParameter("until", until),
               new SqlParameter("administrationId", administrationId)).IgnoreQueryFilters();

评论中提到了这一点,但我一开始错过了这一点,因此将其包括在此处。

我的解决方案是在对原始 sql 查询的结果执行任何操作之前添加.AsEnumerable()

这失败了

var results = ExecuteMyRawSqlQuery(); 
results.Select(r=> r.MyColumn).ToList();

这有效

var results = ExecuteMyRawSqlQuery();
results.AsEnumerable().Select(r=> r.MyColumn).ToList();

在我的情况下,它不起作用,因为我为我的实体类使用了从另一个继承的类。 我创建了一个包含我所有属性的新类,现在它可以工作了

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM