实体框架和存储过程

4
我注意到在Entity Framework设计器中,您可以为插入、更新和删除操作映射存储过程。是否有办法为选择操作执行此操作,还是数据库访问代码的新方向已经不需要编写基本选择操作的存储过程了?
我工作的公司非常坚持始终使用存储过程进行每个数据库操作,即使Entity Framework通过调用sp_executesql使调用变得安全。
似乎LINQ to SQL和Entity Framework都已经摆脱了使用存储过程来选择数据的方式。这是准确的说法吗?
仅澄清我的问题:
我在数据库中有一个名为Product的表。我使用Entity Framework中的向导生成我的模型...所以我现在有一个名为Product的实体。当我执行以下查询时:
db.Products.SingleOrDefault(p => p.Id == 1);

它生成类似于以下代码:
EXEC sp_executesql N'SELECT * FROM Product'

当我真正想要做某事时,比如:
EXEC up_GetProduct @Id = 1

如果使用SingleOrDefault无法实现这一点,那也没关系。我更喜欢以下方式:
db.Products.GetProduct(1);

这是通常会做的事情,还是大多数人只是动态生成SQL语句?
2个回答

7
实体本身不允许选择存储过程。有几个原因:
1. 你如何在存储过程中添加where子句?你要么使用LINQ to Objects执行低效的查询,要么以某种方式能够添加自定义映射到存储过程属性中。虽然这并不是不可能的,但它肯定会引入一些实现复杂性。
2. 实体可以具有用于在查询中执行连接的关系。使用存储过程时,你会再次遇到类似的问题。如果你有Order和OrderItem表,那么如何进行连接?你要么运行SelectOrder,并为每个订单运行SelectOrderItem(1 + n个查询),要么有一个存储过程同时返回两个结果集(其中一个有重复的Order数据),然后你必须指定如何将其映射到实体。如果你必须手动指定映射,则打破了你必须设置的实体关系的目的。
3. 如何进行分页?使用LINQ to Entities,你可以将IQueryable暴露给业务层或UI层(由你决定)。然后你做你的LINQ过滤器来修改SQL并使其高效。使用存储过程,你将再次不得不手动定义所有这些内容,或者使用LINQ to Objects进行过滤。
4. LINQ允许你选择new { o.Column1,o.Column2 }。这将生成仅选择你需要的这两个列的SQL。如果你有一个BLOB / VARCHAR(MAX),那么非常有用。使用存储过程,通常会返回每一列(在许多方面都是浪费的)。你可以拆分为GetOrderDetailMain和GetOrderDetailImages(或类似)存储过程,但创建每个组合并不可行。
在我看来,如果你将使用EF框架,请让它为你执行CRUD。对于全文搜索、特定查询太慢等复杂逻辑,请使用存储过程。否则,你将无法从中获得太多好处。
编辑:当然,存储过程也有好处。它们已经预解析/预编译,是定义良好的“数据库API”,你不需要给表格访问权限(虽然使用SP CRUD,你实际上可以做同样的事情),易于调试/调整查询,易于知道要调整的查询,可以进行批处理等。对于简单的CRUD操作,你必须问自己存储过程的实现/管理开销是否值得。

2
您当然可以在Entity Framework中使用存储过程进行选择操作。我已经成功地使用了函数导入复杂类型和带有EF4的存储过程。而且,它们设置起来也不太困难。
我要警告您一件事:如果您正在使用SQL Server 2005,则可能需要重新编译任何想要与SET FMTONLY OFF一起使用的存储过程,如果您想让实体建模器为您生成复杂类型。有关详细信息,请参见此问题
有关更多信息,请参见快速入门

我已经完成了快速入门。但是我没有看到有关使用存储过程选择数据的内容。 - Dismissile
哦,快速入门那里确实缺乏。试试这个页面,它似乎有更全面的链接集合:http://msdn.microsoft.com/en-us/library/bb738448.aspx - AJ.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接