LINQ表达式如何与存储过程一起使用?

时间:2012-05-13 22:49:46

标签: c# linq entity-framework stored-procedures

我正在处理的新项目的一个要求是所有SQL查询都必须使用存储过程。我将使用Entity Framework&用于管理数据访问的存储库模式,在我的存储库中,我将使用“查找(谓词)”和“FindAll()”方法。目前他们都使用相同的存储过程(“select * from Foo”)。

因为我无法访问SQL事件探查器,所以我不太确定LINQ表达式如何在我的Find(谓词)方法中转换?如果我有类似的东西:

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

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

2 个答案:

答案 0 :(得分:3)

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

你将失去EF的两个优势:

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

如果你不让EF生成查询,你将无法轻松导航,塑造数据,自动生成正确的查询和过滤器等。有些人可以做到这一点,只有你做了一个非常努力的工作模特。但是,如果从数据库更新模型,则可能会丢失一些更改

如果您正在使用EF,那么使用存储过程的合理时机是:

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

对于所有其他查询,让EF为你做的工作要好得多。

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

你必须这样做:

  • 您需要定义尽可能多的实体,因为从存储过程中返回不同的数据
  • 您必须将每个存储过程映射到正确的实体(它们映射到函数),映射到函数或修改模型(edmx)以让它知道用于插入/更新/删除的过程和获得

很难定义一个模型,它具有在它们之间有关系的实体之间的关系。

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

如果让EF创建查询,它会将正确的过滤器发送到数据库(在一个案例中就像你的样本一样)。 如果你有专门的存储过程以特定方式过滤,你将不得不忘记LINQ,并直接调用映射函数。

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

答案 1 :(得分:1)

你是对的,开箱即用的东西会检索所有记录并在内存中过滤。我不会说组合表达式和sprocs是不可能的,但它是非常不切实际的,并且可能首先违背了你的sproc要求的目的。您必须解释表达式树并生成参数化的sql并将其传递给sproc(可能会破坏sproc要求的目的),或者解释表达式树并将参数正确地传递给“generic sproc”。 “Generic”意味着它有任何你想要过滤的可以为零的参数(非常不切实际,并且会有很多限制 - 没有连接等)。

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

即使没有表达式和sprocs之间的可组合性,正如JotaBe所指出的那样,EF仍然可以方便地处理模型并避免使用样板。