ScottGu之博客翻译-第6部分-用存储过程检索数据-LINQ to SQL (Part 6 Retrieving Data Using Stored Procedures)

好像翻译的有些落后了,(因为这周和接下来的几周都会太忙),也好像这些对大家的用处都不是太大了吧。不过我还是希望这些东西能够对初学者们起到一定的帮助作用。
第5部分我很久以前已经试翻译过了,有需要看第5部分的(<asp:Linqtosqldatasource>)请看这里http://www.cnblogs.com/hanxianlong/archive/2007/11/10/955479.html

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

Over the last few weeks I've been writing a series of blog posts that cover LINQ to SQL.  LINQ to SQL is a built-in O/RM (object relational mapper) that ships in the .NET Framework 3.5 release, and which enables you to model relational databases using .NET classes.  You can use LINQ expressions to query the database with them, as well as update/insert/delete data.

上个月我开始了一个讲解LINQ to SQL的帖子系列。LINQ to SQL是集成在.NET Framework3.5中的O/RM(对象关系映射)的实现,它让你非常容易地用.NET类来生成关系型数据库的模型。然后你可以用LINQ 表达式对它来进行查询,更新,插入删除。

Below are the first five parts of my LINQ to SQL series:
下边是我的该系列的前五篇的帖子的链接:

In these previous LINQ to SQL blog posts I demonstrated how you could use LINQ query expressions to programmatically retrieve data from a database.

在这前五篇帖子中,我说明了如何用LINQ的查询表达式通过编程的方式从数据库中检索数据。

In today's blog post I'll cover how you can also use database stored procedures (SPROCs) and user defined functions (UDFs) with your LINQ to SQL data model.  Today's blog post will specifically cover how to call SPROCs to query and retrieve data from the database.  In my next blog post in this series I'll then show how you can optionally also use SPROCs to update/insert/delete data from the database.
在今天的帖子中,我将会讲述一下如何和LINQ to SQL 数据模型一起来使用数据库中的存储过程(SPROCs)和自定义的函数(UDFs)。今天的博客会具体地讲一下如何调用存储过程从数据库中查询和检索数据库。在本系列的下五篇帖子中,我讲会讲一下如何选择用存储过程来更新/插入/删除数据。

To SPROC or not to SPROC?  That is the question...

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

The question of whether to use Dynamic SQL generated by an ORM or instead use Stored Procedures when building a data layer is a topic that generates endless (very passionate) debate amongst developers, architects and DBAs.  A lot of people much smarter than me have written on this topic, so I won't rehash the arguments for and against each side here.

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

The LINQ to SQL ORM that ships in .NET 3.5 is pretty flexible, and can be used to create data model classes whose object model can be independent of the underlying database schema, and which can encapsulate business logic and validation rules that work regardless of whether the data model is populated/persisted via dynamic SQL or via SPROCs.

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

In my LINQ to SQL Part 3: Querying our Database post I discussed how you can write LINQ query expressions against a LINQ to SQL data model using code like below:

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

When you write LINQ query expressions like this the LINQ to SQL ORM will execute the necessary dynamic SQL for you to retrieve Product objects that matches your query.

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

As you'll learn in this post, you can also optionally map SPROCs in the database to your LINQ to SQL DataContext class, which allows you to alternatively retrieve the same Product objects by calling a stored procedure instead:

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

 

This ability to use both dynamic SQL and SPROCs with a clean data model layer is pretty powerful, and provides a great deal of flexibility when working on projects.
这种数据模型的既能调用动态SQL又能调用存储过程能力是非常强大的,并且在对对象的操作上它提供了强大的灵活性。


The Steps to Map and Call a SPROC using LINQ to SQL
在LINQ to SQL中映射和调用存储过程的步骤


In my Part 2: Defining our Data Model Classes tutorial I discussed how to use the LINQ to SQL ORM designer to create a LINQ to SQL class model like below:

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

Notice above how there are two panes on the LINQ to SQL ORM designer surface.  The left pane enables us to define data model classes that map to our database.  The right method pane allows us to optionally map SPROCs (and UDFs) to our LINQ to SQL DataContext object, which we can then use in-place of dynamic SQL to populate the data model objects.

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


How to Map a SPROC to a LINQ to SQL DataContext

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


To map SPROCs to our DataContext class, let's first go to the VS 2008 Server Explorer window and look at the SPROCs within our database:

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

We can double click any of the SPROCs above to open and edit them.  For example, below is the "CustOrderHist" SPROC in Northwind:

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

To map the above SPROC to our LINQ to SQL DataContext, we can drag/drop it from the Server Explorer onto our LINQ to SQL ORM designer.  This will automatically create a new method on our LINQ to SQL DataContext class like below:

为了将上面的存储过程映射到我们的LINQ to SQL DataContext中,我们通过用拖放的方式将它从Server Explorer中拖到我们的LINQ to SQL ORM设计器中。这将自动地在LINQ to SQL DataContext类中生成如下的一个新方法:

By default the method name created on the DataContext class will be the same as the SPROC name, and the return type of the method will be an automatically created type that follows the "[SprocName]Result" naming pattern. For example: the SPROC above would return a sequence of "CustOrderHistResult" objects.  We could optionally change the name of the method by selecting it in the designer and then use the property grid to rename it.
默认情况下,在DataContext为上生成的这个方法的方法名是和存储过程的名称是一样的,并且这个方法的返回值类型的命名方式是“[存储过程名称]结果”。例如,上面的存储过程将会返回一个"CustOrderHistResult"对象序列。我们可以选择将这个方法名进行更改:在设计器上选中它,用属性窗口来对它进行重命名。

How to Call our Newly Mapped SPROC
如何调用我们新映射的存储过程

Once we've done the steps above to map a SPROC onto our DataContext class, it is easy to use it to programmatically retrieve data.  All we need to-do is call the new method we mapped on our DataContext class to get back a sequence of strongly typed results from the SPROC:
做完了上面的映射存储过程到我们的DataContext类的第一步之后,用它来进行编程的方式进行检索数据就很容易了。我们所做的只是来调用映射到我们的DataContext类上的方法来获取从存储过程中返回的一个强类型的序列。


Calling the SPROC in VB:
在VB中调用存储过程:

Calling the Sproc in C#:
在C#中调用存储过程:

In addition to programming looping over the result like in the code samples above, I could also obviously bind the results to any UI control to display them.  For example, the below code databinds the result of our SPROC to a <asp:gridview> control:

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

Which then displays the product history of our customer on a page like so:
在网页上它就会显示出我们客户的产品历史记录:

Mapping the Return Type of SPROC Methods to Data Model Classes
将存储过程的返回值类型映射到数据模型类上

In the "CustOrderHist" SPROC example above the stored procedure returned a sequence of product history results containing two columns of data: the ProductName of the product, and the Total Number of orders the customer has made for that product.  The LINQ to SQL designer automatically defined a new "CustOrderHistResult" class to represent this result.

在上面的"CustOrderHist"例子中,存储过程返回的是一个产品历史记录的序列,这个结果包含了两列数据:Product的ProuctName,客户对那条产品记录下的订单记录的总数。LINQ to SQL设计器自动地定义了一个"CustOrderHistResult"类来展示该结果。

SROC map to an existing data model class we have already defined in the LINQ to SQL designer (for example: an existing Product or Order entity class). 
存储过程映射到了一个我们已经在LINQ to sQL设计器中定义好的数据模型类中(例如,一个已经存在的Product或者Order实体类)。

For example, assume we have a "GetProductsByCategory" SPROC in our database that returns product information like so:

例如,假设在数据库中我们有一个"GetProductByCategory"存储过程,它返回如下的产品信息:

Like before we can create a "GetProductsByCategory" method on our DataContext that calls this SPROC by dragging it onto our LINQ to SQL designer.  Rather than just dropping the SPROC anywhere on the designer, though, we'll instead drop the SPROC on top of the existing "Product" class in our data model designer:

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

This gesture of dropping the SPROC onto the Product class tells the LINQ to SQL designer to have the "GetProductsByCategory" method return a sequence of "Product" objects as a return result:

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

One of the cool things about having our SPROC return "Product" objects like above is that LINQ to SQL will automatically track the changes made to the returned Product objects just like it would Product objects returned via LINQ queries.  When we call the "SubmitChanges()" method on our DataContext, the changes we have made to these objects will automatically be saved back to the database.

将我们的存储过程像上面那样让它返回一个"Product"对象的其中一个非常酷的事情是:linq to sql 将会像跟踪通过linq 查询返回的产品对象那样自动跟踪的通过该存储过程返回的product对象的变化。当我们调用这个DataContext类上的"SubmitChanges()"方法时,我们对该对象所做的任何的变动将会自动地被保存回数据库中。

For example, we could write the code below to retrieve (using a SPROC) and change the price of all products within a specific Category to be 90% of their current value:
例如,我们可以写如下的代码来(用存储过程)检索数据,并且将某一类别的所有产品的价格变为当前值的90%:

When we call SubmitChanges() at the end it will transactionally update all of the product prices.  To understand more about how change tracking and the SubmitChanges() method work, as well as about how Validation Business Logic can be added to data model entities, please read my LINQ to SQL Part 4: Updating our Database tutorial. 

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

In my next blog post in this LINQ to SQL series I'll also cover how you can replace the dynamic insert/update/delete SQL generated by the ORM with custom SPROCs that handle the database updates instead.  The nice thing is that the code above wouldn't change at all if I configured my DataContext to use SPROCs for updates - it would purely be a mapping layer change and the code written against my data model would be oblivious to it. 
在本系列的的下一篇博客中,我也会讲解如何用自定义的存储过程代替动态生成的插入、更新、删除的sql语句来处理数据库的更新。上面代码比较好的一点是,如果我将我的DataContext配置为用存储过程进行更新--那么它就会是一个纯粹的在映射层的变化,并且对我的数据模型所写的代码不会注意到它。

Handling SPROC Output Parameters
处理存储过程的输出参数

LINQ to SQL maps "out" parameters in SPROCs as reference parameters (ref keyword), and for value types declares the parameter as nullable.
linq to sql 将存储过程中的输出参数映射为了一个引用参数(ref keyword),对于值类型的,将参数声明为了可空(nullable)类型。


For example, consider the below "GetCustomerDetails" SPROC which takes a CustomerID as an input parameter, and which returns the company name as an output parameter in addition to its order history as a query result:
例如,看一下下面的这个存储过程"GetCustomerDetails",该存储过程将CustomerID作为输入参数,查询的返回值是该Customer的订单历史以及它的将公司名作为输出参数:

If we drag the above SPROC onto our "Order" class in the LINQ to SQL designer, we could then write the below code to call it:
如果我们将上面的存储过程拖到我们的“Order"类上,我们就可以通过写如下的代码来调用它:


VB
:

C#:

Notice in the code above how the SPROC helper method returns back a sequence of Order objects - but also then returns the CompanyName as an output parameter to the helper method.
注意上面的代码,存储过程助手方法是如何帮助一个产品对象序列的,并且也将CompanyName作为一个输出参数返回给助手方法。


Handling Multiple Result Shapes from SPROCs
处理存储过程返回的多种返回结果

When a stored procedure can return multiple result shapes, the return type of the SPROC method on the DataContext cannot be strongly typed to a single class shape.  For example, consider the SPROC below which returns either a product result or an order result depending on the input parameter:
当一个存储过程可能返回多种结果集是,该在DataContext中的存储过程方法就不可以声明为某单一一种类型的强返回值类型了。例如,看一下如下的存储过程,它根据输出参数的不同可能会返回一个产品结果集,也可以返回一个订单结果集。

LINQ to SQL supports the ability to create SPROC helper methods that can return either a Product or Order shape by adding a partial "NorthwindDataContext" class to the project that defines a method (which in this case we'll call "VariablesShapeSample") that invokes the SPROC and returns an IMultipleResult object like so:
linq to sql 支持生成一个存储过程助手方法来执行该存储过程并且返回一个如下的IMultipleReulst对象,该方法可以通过向项目中添加一个"NorthwindDataContext"类来返回Product或者是Order类型:
VB:

C#:

Once this method is added into our project we can then call it and convert the result to be either a Product or Order sequence when we are using it:
一旦我们该方法添加到我们的项目中,当我们使用的时候就可以调用它并且将结果集或者转换为Product或者是Order序列:


VB:

C#:

Supporting User Defined Functions (UDFs)
对用户自定义函数的支持(UDFS)

In addition to SPROCS, LINQ to SQL also supports both scalar-valued and table-valued user defined functions (UDFs), as well as the in-line counterpart to both.  Once added to your DataContext as a method, you can use these UDF functions within your LINQ queries.
除了支持存储过程,linq to sql 也支持scalar-valued和table-valued的用户自定义函数,存储过程和自定义函数是地位相等同的。一旦将自定义函数作为方法添加到了你的DataContext中,你就可以在linq 查询中使用它们了。

For example, consider a simple scalar user defined function called "MyUpperFunction":
例如,看一下下面这个简单的用户自定义函数"MyUpperFunction":

We can drag/drop it from the Visual Studio Server Explorer onto our LINQ to SQL Designer to add it as a method on our DataContext:

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

We can then use this UDF function inline within our LINQ expressions when writing queries against our LINQ to SQL data model (notice it is being used within the "where" clause below):
当对该linq to sql数据模型来写linq 表达式时,我们就可以用linq表达式来调用该自定义函数(注意它在下面的"where"语句中使用到了):
VB:

C#:

If you use the LINQ to SQL Debug Visualizer that I blogged about here, you can see how LINQ to SQL transforms the above expression queries into raw SQL that execute the UDF inside the database at runtime:

如果你用到了我在博客中(here)说的LINQ to SQL Debug Visualizer,在运行时你就可以看到linq to sql 是如何将上面的表达式转换为原生的sql语句来在数据库中执行自定义的函数的:

Summary
总结

LINQ to SQL supports the ability to call Stored Procedures and UDFs within the database and nicely integrate them into our data model.  In this blog post I demonstrated how you can use SPROCs to easily retrieve data and populate our data model classes.  In my next blog post in this series I'll cover how you can also use SPROCs to override the update/insert/delete logic when you SubmitChanges() on your DataContext to persist back to the database.

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

Hope this helps,

Scott

点个广告:
原文地址:https://www.cnblogs.com/hanxianlong/p/967630.html