简体   繁体   English

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

[英]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 with OFFSET 0 OR TOP 100 PERCENT in the SELECT clause在 SQL Server 上,不与OFFSET 0 OR TOP 100 PERCENTSELECT子句中使用的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 or AsAsyncEnumerable method right after FromSqlRaw or FromSqlInterpolated methods to make sure that EF Core doesn't try to compose over a stored procedure.FromSqlRawFromSqlInterpolated方法之后FromSqlRaw使用AsEnumerableAsAsyncEnumerable方法,以确保 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.

相关问题 EF Core 3.1:Sequence 不包含带有 FromSqlRaw 查询存储过程的元素 - EF Core 3.1: Sequence contains no elements with FromSqlRaw query a stored procedure 如何通过 FromSqlRaw 在 EF Core 3.0 中调用存储过程 - How to call a stored procedure in EF Core 3.0 via FromSqlRaw EF Core FromSQLRaw 和存储过程插入数据 - EF Core FromSQLRaw and Stored Procedures to insert data 如何使用 FromSqlRaw Entity Framework Core 3.1 从存储过程返回多个 SELECT 集 - How to return multiple SELECT sets from a stored procedure using FromSqlRaw Entity Framework Core 3.1 在 EF Core 3.1 中使用可选的返回列执行存储过程 - Execute stored procedure with optional returned columns in EF Core 3.1 带有列变量的 EF Core FromSqlRaw - EF Core FromSqlRaw with column variable 与存储过程一起使用时的 FromSql 方法无法在 EF Core 3.1 中组合 - FromSql method when used with stored procedure cannot be composed in EF Core 3.1 如何从存储过程 EF Core 3.1 中获取多个 OUTPUT 参数 - How to get Multiple OUTPUT parameters from stored procedure EF Core 3.1 使用“FromSqlRaw”命令调用存储过程返回错误 - Calling stored procedure with “FromSqlRaw” command returning an error Mocking 数据库集<t> EF Core 5 中的 .FromSqlRaw</t> - Mocking DbSet<T>.FromSqlRaw in EF Core 5
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM