![](/img/trans.png)
[英]EF Core 3.1: Sequence contains no elements with FromSqlRaw query a stored procedure
[英]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 PERCENT
在SELECT
子句中使用的ORDER BY
子句SQL Server 不允许组合存储过程调用,因此任何将附加查询运算符应用于此类调用的尝试都将导致 SQL 无效。 在
FromSqlRaw
或FromSqlInterpolated
方法之后FromSqlRaw
使用AsEnumerable
或AsAsyncEnumerable
方法,以确保 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.