C# EF核心能否从存储过程/视图/表值函数返回IQueryable?

C# EF核心能否从存储过程/视图/表值函数返回IQueryable?,c#,entity-framework-core,odata,asp.net-core-2.2,ef-core-2.2,C#,Entity Framework Core,Odata,Asp.net Core 2.2,Ef Core 2.2,我们需要将ODATA-V4查询搜索、ORDERBY子句直接传递到数据库 情况如下: 表之间存在连接,我们调用(内联)表值 使用SQL获取所需记录的函数 ODATA其中子句需要应用于结果集,然后 应用分页跳过、接受和按顺序 我们从Dapper开始,但是Dapper只支持IEnumerable,因此Dapper将从DB中获取整个记录,然后只应用OData(查询选项ApplyTo)分页,从而破坏了性能增益:-( [ODataRoute(“LAOData”)] [HttpGet] 公共IQueryabl

我们需要将ODATA-V4查询搜索、ORDERBY子句直接传递到数据库

情况如下:

  • 表之间存在连接,我们调用(内联)表值 使用SQL获取所需记录的函数
  • ODATA其中子句需要应用于结果集,然后 应用分页跳过、接受和按顺序
  • 我们从Dapper开始,但是Dapper只支持IEnumerable,因此Dapper将从DB中获取整个记录,然后只应用OData(查询选项ApplyTo)分页,从而破坏了性能增益:-(

    [ODataRoute(“LAOData”)]
    [HttpGet]
    公共IQueryable GetLAOData(ODataQueryOptions查询选项)
    {
    使用(IDbConnection connection=newSQLConnection(RoutingConstants.CascadeConnectionString))
    {
    
    var sql=“好的,是和否。您当然可以返回一个
    IQueryable
    ,而且您似乎已经在这样做了。而且,您当然可以通过LINQ在内存中进一步查询该
    IQueryable

    我想你真正想问的是,如果你能在数据库级别进一步查询,那么只有你想要的最终结果集才会从数据库中返回。答案是肯定的。必须首先计算存储过程。一旦你这样做了,所有结果都会从数据库中返回。你可以在埃默里,但对数据库来说已经太晚了


    也就是说,您应该理解OData与使用存储过程的想法基本上是不兼容的。整个要点是通过URL参数描述查询—整个查询。您可以使用视图,但存储过程不应与OData一起使用。

    EF无法从Sto返回IQueryablered过程由于数据库引擎本身不提供有选择地查询或操纵脚本执行的机制,因此您不能在SQL中执行以下操作:

    SELECT Field1, Field2
    EXEC dbo.SearchForData_SP()
    WHERE Field2 IS NOT NULL
    ORDER BY Field3
    
    存储过程对于引擎来说是一个黑匣子,因此,某些类型的表达式和操作可以在SPs中使用,而在常规的基于集合的SQL查询或表达式中则无法使用。例如,您可以执行其他存储过程。在处理结果之前,必须完整地执行SPs。

    如果数据库引擎本身无法优化存储过程的执行,那么您的ORM框架将很难做到这一点。 这就是为什么大多数关于通过EF执行SPs的文档和示例都会返回一个
    列表
    ,因为这表明该列表的全部内容都在内存中,并使用
    将该
    列表
    强制转换为
    IQueryable
    。AsQueryable()
    不会改变数据在该列表对象中维护的事实

  • 表之间存在连接,我们使用SQL调用(内联)表值函数以获得所需的记录
  • 您所描述的类似于ODATA和EF试图为您提供的复杂查询机制。为了充分利用ODATA和EF,您应该考虑用LINQ语句复制或替换TVFS。EF是RDBMS不可知的,因此它试图使用和执行可应用于许多数据库E的通用标准。ngines,不仅仅是SQLSERVER。当涉及到cte、TVFs和SPs时,每个数据库引擎中的实现和语法在某些情况下甚至对特定的版本都变得更加具体。EF团队不是试图成为每个人的一切,而是必须实施一些限制,以便他们能够保持为我们提供的服务的质量。

    然而,有一个令人满意的媒介是可以实现的,您可以利用两个引擎的功率:

  • 设计您的SP,以便将筛选变量作为参数传递,并将对存储过程的依赖性限制在输出结构与您通常需要的一样高效的情况下。然后,您可以在
    OData
    中将SP公开为
    操作
    端点,被调用方可以传递参数values直接连接到SP

    • 您仍然可以将响应包装在
      IQueryable
      中,并使用
      EnableQuery
      属性修饰此操作,这将在内存中执行$select、$expand和简单的$filter操作,但在构建响应负载之前,服务仍将整个记录集加载到内存中。此机制仍然可以减少服务器和客户端之间的带宽,而不是数据库和服务层之间的带宽
    • 如果需要针对不同的用例使用不同的结果结构,请制作不同版本的SP
  • 仅当查询过于复杂,无法使用linq轻松表达,或者需要使用无法在linq中轻松复制的表提示、CTE、递归CTE或窗口函数时,才使用
    TVFs
    Views

    • 在许多使用CTE(非递归)的情况下,可以更容易地在Linq中构造表达式
    • 为了从索引中获得最大的性能,您可以在SQL中使用表提示,因为我们无法严格控制Linq表达式将如何组合到SQL中,因此以数据库可以为我们优化的方式构造一些查询可能需要大量的工作。在许多情况下,与上面的CTE一样,需要经历以下过程:在Linq中重写查询有助于避免传统上使用表提示的情况

      • 当您想要或需要使用EF不支持的专门SQL Server概念进行控制时,会有一些限制,您会有意识地决定使用其中一个而不是另一个
  • 我不同意OData和存储过程从根本上是不兼容的
    SELECT Field1, Field2
    EXEC dbo.SearchForData_SP()
    WHERE Field2 IS NOT NULL
    ORDER BY Field3