[英]Include with FromSqlRaw and stored procedure in EF Core 3.1
So here's the deal - I am currently using EF Core 3.1 and let's say I have an entity:所以这是交易 - 我目前正在使用 EF Core 3.1 并且假设我有一个实体:
public class Entity
{
public int Id { get; set; }
public int AnotherEntityId { get; set; }
public virtual AnotherEntity AnotherEntity { get; set; }
}
When I access the DbSet<Entity> Entities
normal way, I include AnotherEntity like:当我以正常方式访问
DbSet<Entity> Entities
时,我将 AnotherEntity 包括在内,例如:
_context.Entities.Include(e => e.AnotherEntity)
and this works.这有效。 Why wouldn't it, right?
为什么不呢,对吧? Then I go with:
然后我 go 与:
_context.Entities.FromSqlRaw("SELECT * FROM Entities").Include(e => e.AnotherEntity)
and this also works.这也有效。 Both return me the same collection of objects joined with AnotherEntity.
两者都返回与 AnotherEntity 连接的相同对象集合。 Then I use a stored procedure which consists of the same query
SELECT * FROM Entities
named spGetEntities:然后我使用一个存储过程,它包含相同的查询
SELECT * FROM Entities
:
_context.Entities.FromSqlRaw("spGetEntities")
guess what?你猜怎么了? This also works.
这也有效。 It gives me the same output but without joined AnotherEntity, obviously.
它给了我相同的 output 但显然没有加入 AnotherEntity。 However if I try to add the Include like this:
但是,如果我尝试像这样添加 Include :
_context.Entities.FromSqlRaw("spGetEntities").Include(e => e.AnotherEntity)
I am getting:我正进入(状态:
FromSqlRaw or FromSqlInterpolated was called with non-composable SQL and with a query composing over it.
FromSqlRaw 或 FromSqlInterpolated 是使用不可组合的 SQL 调用的,并在其上组合了一个查询。 Consider calling
AsEnumerable
after the FromSqlRaw or FromSqlInterpolated method to perform the composition on the client side.考虑在 FromSqlRaw 或 FromSqlInterpolated 方法之后调用
AsEnumerable
以在客户端执行组合。
Even though the output of _context.Entities.FromSqlRaw("SELECT * FROM Entities")
and _context.Entities.FromSqlRaw("spGetEntities")
is identical.即使
_context.Entities.FromSqlRaw("SELECT * FROM Entities")
和_context.Entities.FromSqlRaw("spGetEntities")
的 output 是相同的。
I couldn't find a proof that I can or I can not do this with EF Core 3.1 but if someone could give me any hint of possibility of this approach it would be nice.我找不到证据证明我可以或不能用 EF Core 3.1 做到这一点,但如果有人能给我任何关于这种方法可能性的暗示,那就太好了。
Also if there is another way to get joined entities using stored procedure I would probably accept it as the solution of my issue.另外,如果有另一种方法可以使用存储过程来连接实体,我可能会接受它作为我的问题的解决方案。
Shortly, you can't do that (at least for SqlServer).很快,您不能这样做(至少对于 SqlServer)。 The explanation is contained in EF Core documentation - Raw SQL Queries - Composing with LINQ :
解释包含在 EF Core 文档 - Raw SQL Queries - Composing with LINQ 中:
Composing with LINQ requires your raw SQL query to be composable since EF Core will treat the supplied SQL as a subquery.
使用 LINQ 进行组合要求原始 SQL 查询是可组合的,因为 EF Core 会将提供的 SQL 视为子查询。 SQL queries that can be composed on begin with the
SELECT
keyword.可以组合的 SQL 查询以
SELECT
关键字开始。 Further, SQL passed shouldn't contain any characters or options that aren't valid on a subquery, such as:此外,传递的 SQL 不应包含任何对子查询无效的字符或选项,例如:
- A trailing semicolon
尾随分号
- On SQL Server, a trailing query-level hint (for example,
OPTION (HASH JOIN)
)在 SQL Server 上,尾随查询级提示(例如,
OPTION (HASH JOIN)
)- On SQL Server, an
ORDER BY
clause that isn't used withOFFSET 0 OR TOP 100 PERCENT
in theSELECT
clause在 SQL Server 上,不与
OFFSET 0 OR TOP 100 PERCENT
在SELECT
子句中使用的ORDER BY
子句SQL Server doesn't allow composing over stored procedure calls, so any attempt to apply additional query operators to such a call will result in invalid SQL.
SQL Server 不允许组合存储过程调用,因此任何将附加查询运算符应用于此类调用的尝试都将导致 SQL 无效。 Use
AsEnumerable
orAsAsyncEnumerable
method right afterFromSqlRaw
orFromSqlInterpolated
methods to make sure that EF Core doesn't try to compose over a stored procedure.在
FromSqlRaw
或FromSqlInterpolated
方法之后FromSqlRaw
使用AsEnumerable
或AsAsyncEnumerable
方法,以确保 EF Core 不会尝试组合存储过程。
Additionally, since Include
/ ThenInclude
require EF Core IQueryable<>
, AsEnumerable
/ AsAsyncEnumerable
etc. is not an option.此外,由于
Include
/ ThenInclude
需要 EF Core IQueryable<>
, AsEnumerable
/ AsAsyncEnumerable
等不是一个选项。 You really need composable SQL, hence stored procedures are no option.您确实需要可组合的 SQL,因此没有选择存储过程。
Instead of stored procedures though, you can use Table-Valued Functions (TVF) or database views because they are composable ( select * from TVF(params)
or select * from db_view
) .不过,您可以使用表值函数 (TVF) 或数据库视图代替存储过程,因为它们是可组合的(
select * from TVF(params)
或select * from db_view
)。
In my case I was converting working EF FromSql()
with a stored procedure 2.1 code to 3.1.就我而言,我正在将带有存储过程 2.1 代码的工作 EF
FromSql()
转换为 3.1。 Like so:像这样:
ctx.Ledger_Accounts.FromSql("AccountSums @from, @until, @administrationId",
new SqlParameter("from", from),
new SqlParameter("until", until),
new SqlParameter("administrationId", administrationId));
Where AccountSums
is a SP.其中
AccountSums
是 SP。
The only thing I had to do was use FromSqlRaw()
and add IgnoreQueryFilters()
to get it working again.我唯一需要做的就是使用
FromSqlRaw()
并添加IgnoreQueryFilters()
让它再次工作。 Like so:像这样:
ctx.Ledger_Accounts.FromSqlRaw("AccountSums @from, @until, @administrationId",
new SqlParameter("from", from),
new SqlParameter("until", until),
new SqlParameter("administrationId", administrationId)).IgnoreQueryFilters();
This is mentioned in the comments, but I missed that at first so including this here.评论中提到了这一点,但我一开始错过了这一点,因此将其包括在此处。
The solution for me was to add .AsEnumerable() before performing any operation on the result of the raw sql query.我的解决方案是在对原始 sql 查询的结果执行任何操作之前添加.AsEnumerable() 。
this fails这失败了
var results = ExecuteMyRawSqlQuery();
results.Select(r=> r.MyColumn).ToList();
this works这有效
var results = ExecuteMyRawSqlQuery();
results.AsEnumerable().Select(r=> r.MyColumn).ToList();
In my case it wasn't working because I used a class that inherit from another for my entity class.在我的情况下,它不起作用,因为我为我的实体类使用了从另一个继承的类。 I created a new class with all my porperties and now its working
我创建了一个包含我所有属性的新类,现在它可以工作了
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.