【问题标题】:Include with FromSqlRaw and stored procedure in EF Core 3.1在 EF Core 3.1 中包含 FromSqlRaw 和存储过程
【发布时间】:2020-04-10 09:16:51
【问题描述】:

这就是交易 - 我目前正在使用 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 时,我包含了另一个实体,例如:

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

这行得通。为什么不呢,对吧?然后我去:

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

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

_context.Entities.FromSqlRaw("spGetEntities")

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

_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 做到这一点,但如果有人能给我任何暗示这种方法的可能性,那就太好了。

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

【问题讨论】:

  • 这不是 EF 做不到的。它是 SQL 本身(“不可组合的 SQL”),所以更不用说 EF 了。
  • @GertArnold 请将其添加为答案。它也会帮助其他用户。
  • _context.Something.FromSqlRaw("EXECUTE dbo.spCreateSomething @Id, @Year", sqlParameters).IgnoreQueryFilters().AsNoTracking().AsEnumerable().FirstOrDefault();这对我有用,你可以使用 ToList() 以及 .AsEnumerable().FirstOrDefault() 来获得很多。

标签: c# .net entity-framework join entity-framework-core


【解决方案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 上,ORDER BY 子句在 SELECT 子句中不与 OFFSET 0 OR TOP 100 PERCENT 一起使用

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

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

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

【讨论】:

  • 这在我的情况下不起作用,因为我使用的是派生类型。当使用模型中使用的类型的派生类型时,即使您在 FromSqlRaw 之后立即调用 AsEnumerable,查询也会组合。除了使该类型不派生,与基类型的所有属性分开之外,我没有看到其他解决方案,这很不方便。
  • @HrvojeBatrnek 我猜你想到了stackoverflow.com/questions/61070935/…
【解决方案2】:

在我的例子中,我将使用存储过程 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();

这在 cmets 中有提到,但我一开始错过了,所以在这里包括这个。

【讨论】:

  • 所以 AccountSums 是一个 SP 而 @from 是另一个包含实体子导航的连接?看起来真的很奇怪..这样做..你能给你一个用法示例吗?
  • 和SP参数
  • 好的,但这是否回答了最初的问题?因为我的理解是没有......也许我错过了一些东西
  • 如果您有机会,请分享更多您的代码。我尝试了您的方法,但仍然收到该死的“不可组合 SQL”错误。我正在使用 .Net 6/EntityFrameworkCore 6.0.1,但它可能又坏了。
  • 没有更多的代码.. 我猜你有不同的问题
【解决方案3】:

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

这失败了

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

这行得通

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

【讨论】:

  • 嗨。您应该知道,一旦您将.AsEnumerable() 应用于您的数据库集,所有记录都会被评估到内存中。因此,任何对数据进行转换、过滤和排序的进一步操作都在执行机器上执行。
【解决方案4】:

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

【讨论】:

    猜你喜欢
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-10
    • 2021-03-06
    • 2020-11-23
    • 1970-01-01
    相关资源
    最近更新 更多