LINQ 表达式如何使用存储过程

本文关键字:存储过程 何使用 表达式 LINQ | 更新日期: 2023-09-27 18:33:59

我对正在处理的新项目的要求之一是所有SQL查询都必须使用存储过程。我将使用实体框架和存储库模式来管理数据访问,在我的存储库中,我将使用"Find(谓词("和"FindAll( ("方法。目前,它们都使用相同的存储过程("从Foo中选择*"(。

鉴于我无法访问 SQL 事件探查器,我不太确定 LINQ 表达式在我的 Find( 谓词( 方法中将如何转换?如果我有这样的东西:

List<Foo> myFoo = repository.Find( f => f.Country == "Australia" && f.Status = "New" );

我假设这将通过 sproc 检索所有记录,并将结果数据在内存中过滤是否正确?如果是这种情况,我如何构建 sproc 以仅检索所需的记录,同时允许使用 linq 表达式(需要允许 &&、||、!= 等(?这甚至有可能在不放弃 sproc 的情况下实现吗?

LINQ 表达式如何使用存储过程

如果您被迫对所有内容使用存储过程,则使用 EF 没有多大意义。事实上,EF 的最大优点之一是它自动生成查询,具有最严格的参数数量和正确的查询 sintax 来获取/插入/更新/删除数据。

您将失去 EF 的两个优点:

  • 导航,即通过急切、显式或延迟加载轻松获取相关数据
  • 形状数据,即获取具有其他实体或实体集合的属性的实体
  • 自动生成简单的 CRUD 操作(惰性/更新/删除/选择(。您可以为此操作指定 stoed 进程
  • 如果数据库更改只是更改模型,则获取正确的查询(这几乎可以自动,具体取决于您使用 EF 的方式( 如果数据更改,则必须修改相关的存储过程*自动生成对即席筛选器的查询(在不同列上具有不同条件集的筛选器(

如果不让 EF 生成查询,您将无法轻松导航、调整数据、自动生成正确的查询和筛选器等。但是,如果您从数据库中更新模型,则某些更改可能会丢失

如果使用 EF,则证明使用存储过程的情况是:

    需要修改 EF
  • 无法直接修改的数据(即,不支持旧版本的 EF 中的可更新查询(
  • 你已优化要使用的存储过程,而不是 EF 生成的查询,即优化的复杂筛选器
  • 存储的过程,可以做很多事情(那些不是简单的插入/更新/删除或选择过程的过程(
  • 存储过程比自动生成的查询具有某种优势的任何其他场合。

对于所有其他查询,最好让 EF 为你完成工作。

如果需要对所有内容使用存储过程,则使用 EF 的优势是将数据自动映射到实体,但你将失去 EF 的许多其他优势。

您必须执行以下操作:

  • 您需要定义从存储过程返回的不同数据时尽可能多的实体
  • 您必须将每个存储的过程映射到正确的实体(它们映射到函数(、函数或修改模型 (edmx( 以让它知道使用哪个过程插入/更新/删除并获取
很难定义一个模型,该模型具有实体

之间的关系,而实体之间有关系。

至于在最好的情况下repository.Find(...)的问题,你是对的,所有数据都会被查询,然后在客户端进行过滤。在最坏的情况下,如果模型未正确定义,则可能会失败。

如果让 EF 创建查询,它会将正确的筛选器发送到数据库(在与示例类似的单一情况下(。如果您有以特定方式进行筛选的专用存储过程,则必须忘记 LINQ,并直接调用映射的函数。

因此,除非确实有充分的理由使用 SP,否则最好让 EF 为您创建查询。

您是对的,您正在做的开箱即用将检索所有记录并在内存中过滤。 我不会说编写表达式和 sproc 是不可能的,但这是非常不切实际的,并且可能首先违背了您的 sproc 要求的目的。 您必须解释表达式树并生成参数化的sql并将其传递给sproc(可能违背了sproc要求的目的(,或者解释表达式树并将参数正确传递给"通用sproc"。 "通用"意味着它对您想要过滤的任何内容都有可为空的参数(非常不切实际,并且会有很多限制 - 没有连接等(。

如果您尊重 sproc 要求,我会放弃任何公开 IQueryable 的数据访问 api(除非您愿意在内存中执行表达式,否则您将失去编写表达式和 sproc 的能力(。

正如JotaBe所指出的,即使表达式和sprocs之间没有可组合性,EF仍将在处理模型和避免相当样板的ado时提供便利。