1

我正在处理的一个新项目的要求之一是所有 SQL 查询都必须使用存储过程。我将使用实体框架和存储库模式来管理数据访问,并且在我的存储库中我将拥有“Find(predicate)”和“FindAll()”方法。目前他们都使用相同的存储过程(“select * from Foo”)。

看到我无法访问 SQL Profiler,我不太确定 LINQ 表达式将如何在我的 Find(predicate) 方法中转换?如果我有类似的东西:

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

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

4

2 回答 2

3

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

您将失去 EF 的两个优势:

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

如果您不让 EF 生成查询,那么您将无法轻松导航、塑造数据、自动生成正确的查询和过滤器等。只有在模型中付出非常努力的工作,他才有可能。但是,如果您从数据库中更新模型,您的某些更改可能会丢失

如果您使用的是 EF,则可以使用存储过程的场合是:

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

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

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

你必须这样做:

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

很难定义一个模型,该模型具有实体之间的关系,而这些实体之间存在关系。

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

如果您让 EF 创建查询,它将向数据库发送正确的过滤器(在单个情况下,例如您的示例)。如果您有以特定方式过滤的专用存储过程,您将不得不忘记 LINQ,并直接调用映射函数。

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

于 2012-05-14T01:22:22.563 回答
1

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

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

正如 JotaBe 所指出的,即使表达式和存储过程之间没有可组合性,EF 仍将在处理模型方面提供便利,并避免相当多的样板文件。

于 2012-05-14T01:28:18.573 回答