LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures
本文转载自:
http://www.cnblogs.com/hanxianlong/archive/2007/11/25/967630.html

英文原贴链接:
http://weblogs.asp.net/scottgu/archive/2007/08/16/linq-to-sql-part-6-retrieving-data-using-stored-procedures.aspx

在这前五篇帖子中,我说明了如何用LINQ的查询表达式通过编程的方式从数据库中检索数据。在今天的帖子中,我将会讲述一下如何和LINQ to SQL 数据模型一起来使用数据库中的存储过程(SPROCs)和自定义的函数(UDFs)。今天的博客会具体地讲一下如何调用存储过程从数据库中查询和检索数据库。在本系列的下五篇帖子中,我讲会讲一下如何选择用存储过程来更新/插入/删除数据。


使用存储过程还是不使用?这是个问题....

在建立数据层时是使用ORM生成的动态SQL语句还是用存储过程这个问题在开发者,架构师和DBA之间一直争论不休。许多比我聪明的人已经写过此话题, 所以在此我不想重复地谈论是赞成还是反对这个问题。

在.NET 3.5中的LINQ to SQL ORM非常灵活,你可以用来生成数据模型类,该数据模型类可以独立于数据库中的数据结构,而且可以写入无论是使用动态生成的SQL还是存储过程都可以执行的业务逻辑和验证规则。

在第3部分LINQ to SQL Part 3: Querying our Database:查询数据库这篇帖子中,我讨论了如何对LINQ to SQL数据模型像下面这样写LINQ的查询表达式:

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第1张图片

图1

当你像这样写LINQ 查询表达式时,LINQ to SQL 模型将会执行必要的动态SQL语句来检索出跟你的查询匹配的产品对象。

在这篇帖子中你将学到,你也可以选择将数据库中的存储过程遇到到你的LINQ to SQL DataContext类中,存储过程会允许你调用它来完成对产品对象的检索功能。

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第2张图片

图2

这种数据模型的既能调用动态SQL又能调用存储过程能力是非常强大的,并且在对对象的操作上它提供了强大的灵活性。

在LINQ to SQL中映射和调用存储过程的步骤

在第二部分我讲述了如何用LINQ to SQL ORM设计器来生成一个如下的LINQ to SQL类模型:

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第3张图片
图3

注意,在上边的LINQ to SQL ORM设计器中有两个面板。左侧的面板使我们可以定义映射到我们数据库的数据模型。右侧的面板允许我们有选择的映射存储过程(和自定义的函数)到我们的LINQ to sQL DataContexxt对象,这个映射的存储过程可以允许我们用它来代替动态生成的SQL语句来从该数据模型对象中查找数据。

如何将存储过程映射到LINQ to SQL DataContext

为了映射存储过程到我们的DataContext类中,让我们产生到VS2008中的Server Explorer窗口,看一下在数据库中的存储过程:

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第4张图片

图4

我们可以双击存储过程来打开和编辑它们,例如,下面是在Northwind中的“CustOrderHist"的存储过程:

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第5张图片

图5

为了将上面的存储过程映射到我们的LINQ to SQL DataContext中,我们通过用拖放的方式将它从Server Explorer中拖到我们的LINQ to SQL ORM设计器中。这将自动地在LINQ to SQL DataContext类中生成如下的一个新方法:
LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第6张图片

图6

默认情况下,在DataContext为上生成的这个方法的方法名是和存储过程的名称是一样的,并且这个方法的返回值类型的命名方式是“[存储过程名称]结果”。例如,上面的存储过程将会返回一个"CustOrderHistResult"对象序列。我们可以选择将这个方法名进行更改:在设计器上选中它,用属性窗口来对它进行重命名。

如何调用我们新映射的存储过程

做完了上面的映射存储过程到我们的DataContext类的第一步之后,用它来进行编程的方式进行检索数据就很容易了。我们所做的只是来调用映射到我们的DataContext类上的方法来获取从存储过程中返回的一个强类型的序列。

在VB中调用存储过程:
LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第7张图片

图7
在C#中调用存储过程:

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第8张图片

图8

除了像上面那样对结果集进行遍历之外,我还可以将结果集绑定到UI上并将它们显示出来。例如,下面的代码将我们的存储过程的结果集绑定到了<asp:gridview>控件上:

图9


在网页上它就会显示出我们客户的产品历史记录:

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第9张图片
图10

将存储过程的返回值类型映射到数据模型类上

在上面的"CustOrderHist"例子中,存储过程返回的是一个产品历史记录的序列,这个结果包含了两列数据:Product的ProuctName,客户对那条产品记录下的订单记录的总数。LINQ to SQL设计器自动地定义了一个"CustOrderHistResult"类来展示该结果。存储过程映射到了一个我们已经在LINQ to sQL设计器中定义好的数据模型类中(例如,一个已经存在的Product或者Order实体类)。例如,假设在数据库中我们有一个"GetProductByCategory"存储过程,它返回如下的产品信息:

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第10张图片
图11

像以前那样,我们通过拖放的方式将存储过程拖到我们的LINq to sql 设计器上来在我们的DataContext中生成一个"GetProductsByCategory"方法。这次不是将这个存储过程拖到设计器任意位置,而是将它拖到在数据模型设计器中已经存在的“Product"类上:

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第11张图片

图12

将存储过程拖到Product类上的这种行为就告诉了linq to sql 设计器,使"GetProductCategory"方法的返回一个“Product"对象:

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第12张图片

图13

将我们的存储过程像上面那样让它返回一个"Product"对象的其中一个非常酷的事情是:linq to sql 将会像跟踪通过linq 查询返回的产品对象那样自动跟踪的通过该存储过程返回的product对象的变化。当我们调用这个DataContext类上的"SubmitChanges()"方法时,我们对该对象所做的任何的变动将会自动地被保存回数据库中。例如,我们可以写如下的代码来(用存储过程)检索数据,并且将某一类别的所有产品的价格变为当前值的90%:

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第13张图片

图14

在最后调用SubmitChange()方法是,它就会自动地通过调用事务对所有的产品的价格进行更新。若想学习更多的关于如何跟踪变化和SubmitChanges()是如何工作的,如何将验证业务逻辑添加到我们的数据模型实体是,请阅读我的第四部分(LINQ to SQL Part 4: Updating our Database)。

在本系列的的下一篇博客中,我也会讲解如何用自定义的存储过程代替动态生成的插入、更新、删除的sql语句来处理数据库的更新。上面代码比较好的一点是,如果我将我的DataContext配置为用存储过程进行更新--那么它就会是一个纯粹的在映射层的变化,并且对我的数据模型所写的代码不会注意到它。

处理存储过程的输出参数

将存储过程中的输出参数映射为了一个引用参数(ref keyword),对于值类型的,将参数声明为了可空(nullable)类型。 例如,看一下下面的这个存储过程"GetCustomerDetails",该存储过程将CustomerID作为输入参数,查询的返回值是该Customer的订单历史以及它的将公司名作为输出参数:

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第14张图片

图15

如果我们将上面的存储过程拖到我们的“Order"类上,我们就可以通过写如下的代码来调用它:

VB:
LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第15张图片

图16

C#:
LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第16张图片

图17

注意上面的代码,存储过程助手方法是如何帮助一个产品对象序列的,并且也将CompanyName作为一个输出参数返回给助手方法。

处理存储过程返回的多种返回结果

当一个存储过程可能返回多种结果集是,该在DataContext中的存储过程方法就不可以声明为某单一一种类型的强返回值类型了。例如,看一下如下的存储过程,它根据输出参数的不同可能会返回一个产品结果集,也可以返回一个订单结果集。

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第17张图片

图18

linq to sql 支持生成一个存储过程助手方法来执行该存储过程并且返回一个如下的IMultipleReulst对象,该方法可以通过向项目中添加一个"NorthwindDataContext"类来返回Product或者是Order类型:
VB:

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第18张图片

图19

C#:
LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第19张图片

图20

一旦我们该方法添加到我们的项目中,当我们使用的时候就可以调用它并且将结果集或者转换为Product或者是Order序列:

VB:
LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第20张图片

图21

C#:
LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第21张图片

图22

对用户自定义函数的支持

除了支持存储过程,linq to sql 也支持scalar-valued和table-valued的用户自定义函数,存储过程和自定义函数是地位相等同的。一旦将自定义函数作为方法添加到了你的DataContext中,你就可以在linq 查询中使用它们了。例如,看一下下面这个简单的用户自定义函数"MyUpperFunction":

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第22张图片

图23

我们可以通过将它从VS Server Explorer中拖到linq to sql 设计器中,作为我们的DataContext上的一个方法添加进来:

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第23张图片

图24

当对该linq to sql数据模型来写linq 表达式时,我们就可以用linq表达式来调用该自定义函数(注意它在下面的"where"语句中使用到了):
VB:

图25

C#:

LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第24张图片

图26

如果你用到了我在博客中(here)说的LINQ to SQL Debug Visualizer,在运行时你就可以看到linq to sql 是如何将上面的表达式转换为原生的sql语句来在数据库中执行自定义的函数的:
LINQ to SQL系列Part 6 - Retrieving Data Using Stored Procedures_第25张图片

图27


总结

linq to sql 支持调用数据库中的存储过程和自定义函数,并且能够很好地将它们和我们的数据库模型进行集成。在这篇博客中我讲述了如何通过调用存储过程来方便地检索数据并且从数据模型类中取出我们需要的数据来。在下本系列的下一篇博客中,我将会讲解在调用SubmitChanges()方法将变动保存至数据库中时,如何调用存储过程来替代更新、插入、删除逻辑。

Scott

你可能感兴趣的:(sql,sql,server,vb,VB.NET,LINQ)