希望本贴能对您的LINQ to SQL语言的学习有一定的帮助!
原贴链接:
http://weblogs.asp.net/scottgu/archive/2007/06/29/linq-to-sql-part-3-querying-our-database.aspx
Last month I started a blog post series covering LINQ to SQL. LINQ to SQL is a built-in O/RM (object relational mapping) framework that ships in the .NET Framework 3.5 release, and which enables you to easily model relational databases using .NET classes. You can then use LINQ expressions to query the database with them, as well as update/insert/delete data from it.
上个月我开始了一个讲解LINQ to SQL的帖子系列。LINQ to SQL是集成在.NET Framework3.5中的O/RM(对象关系映射)的实现,它让你非常容易地用.NET类来生成关系型数据库的模型。然后你可以用LINQ 表达式对它来进行查询,更新,插入删除。
Below are the first two parts of my LINQ to SQL series:
下边是我的前两篇的帖子的链接:
In today's blog post I'll be going into more detail on how to use the data model we created in the Part 2 post, and show how to use it to query data within an ASP.NET project.
在今天的帖子中,我将会更详细地讲解一下如何使用我们在第2部分(Part 2 )中生成数据模型,并且讲解一下如何在ASP.NET项目中使用它来查询数据。
Northwind Database Modeled using LINQ to SQL
用LINQ to SQL生成的Northwind数据库
In Part 2 of this series I walked through how to create a LINQ to SQL class model using the LINQ to SQL designer that is built-into VS 2008. Below is the class model that we created for the Northwind sample database:
在本系列的第2部分(Part 2)中,我讲解了如何用VS2008中的LINQ to SQL设计器来生成LINQ to SQL类模型。下面是从Northwind事例数据库生成的类模型:
Retrieving Products
查询产品
Once we have defined our data model classes above, we can easily query and retrieve data from our database. LINQ to SQL enables you to do this by writing LINQ syntax queries against the NorthwindDataContext class that we created using the LINQ to SQL designer above.
一旦我们定义了如上的数据模型类,我们就可以非常方便地从数据库中查询并且检索数据。LINQ to SQL允许你通过对上边的用LINQ to SQL设计器生成的NorthwindDataContext类写LINQ语句来对数据库进行查询和检索。
For example, to retrieve and iterate over a sequence of Product objects I could write code like below:
例如,我可以通过写如下的代码来查过和对产品对象序列进行循环查询:
In the query above I haveused a "where" clause in my LINQ syntax query to only return those products within a specific category. I am using the CategoryID of the Product to perform the filter.
在上边的查询中,我在LINQ 语句中用"where"语句来限定仅返回属于某种特定类型的产品。这里我是用Product的CategoryID作为过滤条件。
One of the nice things above LINQ to SQL is that I have a lot of flexibility in how I query my data, and I can take advantage of the associations I've setup when modeling my LINQ to SQL data classes to perform richer and more natural queries against the database. For example, I could modify the query to filter by theproduct's CategoryName instead of its CategoryID by writing my LINQ query like so:
上边的LINQ to SQL的其中一个比较好的地方是,在如何查询数据这个问题上有很大的灵活性,并且我可以用已经先定义在LINQ to SQL 数据类中的关联来对数据库进行更丰富和更自然的查询。例如,我可以像如下这样更改我的代码以实现对产品用类别名而不是用类别ID进行查询:
Notice above how I'm using the "Category" property that is on each of the Product objects to filter by the CategoryName of the Category that the Product belongs to. This property was automatically created for us by LINQ to SQL because we modeled the Category and Product classes as having a many to one relationship with each other in the database.
注意上边我是如何用每个Product对象的”Category"属性来来对产品对象列表通过类别名称进行过滤。这个属性是LINQ to SQL自动为我们生成的,因为我们将数据库的Category和Product表有一对多的关系也生成在了Category和Product类之间了。
For another simple example of using our data model's association relationships within queries, we could write the below LINQ query to retrieve onlythose products that have had 5 or more orders placed for them:
下面是另外一个简单的在查询中使用生成的关联关系进行查询的小例子,我可以通过写如下的LINQ查询语句来查出超过5条订单详细信息的产品列表:
Notice above how we are using the"OrderDetails" collection that LINQ to SQL has created for us on each Product class (because of the 1 to many relationship we modeled in the LINQ to SQL designer).
注意我们用的"OrderDetails"集合,它是LINQ to SQL已经为我们在每个Product类上生成好的(因为我们用LINQ to SQL设计器生成的有一对多的关系)。
Visualizing LINQ to SQL Queries in the Debugger
在调试状态下查看LINQ to SQL查询
Object relational mappers like LINQ to SQL handle automatically creating and executing the appropriate SQL code for you when you performa query or update against their object model.
当你对像LINQ to SQL这样的对象关系映射生成的对象模型进行查询或者更新时,它们会自动地处理生成和执行适合的SQL语句。
One of the biggest concerns/fears that developers new to ORMs have is "but what SQL code is it actually executing?" One of the really nice things about LINQ to SQL is that it makes it supereasy to see exactly what SQL code it is executing when you run your application within the debugger.
和开发者对ORMs关联并且困扰着他们的是“它实际上执行的是什么SQL语句?“,LINQ to SQL真正好的一处是它可以在调试状态下运行程序时,很方便地看它执行了什么SQL代码。
Starting with Beta2 of Visual Studio 2008 you can use a new LINQ to SQL visualizer plug-in to easily see (and test out) any LINQ to SQL query expression. Simply set a breakpoint and then hover over a LINQ to SQL query and click the magnify glass to pull up its expression visualizer within the debugger:
用VS2008Beta2作为开始,你可以用一个新的LINQ to SQL可视化插件来方便地查询(测试出)任何的LINQ to SQL查询表达式。简单地设计一个断点,然后在调试状态下将鼠标放到LINQ to SQL查询,点击放大器来将查看查询表达式。
This will then bring up a dialog that shows you the exact SQL that LINQ to SQL will use when executing the query to retrieve the Product objects:
然后,这个操作就会弹出一个窗口,该窗口中展示的就是你在用该LINQ to SQL检索产品对象时用到的完整的SQL语句:
If you press the "Execute" button within this dialog it will allow you to evaluate the SQL directly within the debugger and see the exact data results returned from the database:
如果在该对话框中你点击“Execute”,它会直接在调试器中执行SQL语句并且能够查询从数据库中返回的数据:
This obviously makes it super easy to see precisely what SQL query logic LINQ to SQL is doing for you. Note that you can optionally override the raw SQL that LINQ to SQL executes in cases where you want to change it - although in 98% of scenarios I think you'll find that the SQL code that LINQ to SQL executes is really, really good.
很明显,这使得你查看LINQ to SQL为你生成的精确的SQL查询逻辑变得非常地方便。注意,如果想改变它,你也可以选择重写LINQ to SQL为你生成的SQL语句--虽然在98%的情况下我想你会发现LINQ to SQL执行的SQL语句非常非常地好。
Databinding LINQ to SQL Queries to ASP.NET Controls
将LINQ to SQL的查询和ASP.NET 的控件绑定
LINQ queries return results that implement the IEnumerable interface - which is also an interface that ASP.NET server controls support to databind object. What this means is that you can databind the results of any LINQ, LINQ to SQL, or LINQ to XML query to any ASP.NET control.
LINQ 查询返回一个实现了IEnumerable接口的集合--IEnumerable也是支持数据绑定的ASP.NET服务器控件实现的接口。说这个的意思就是你可以将任何的LINQ,LINQ to SQL或LINQ to XML查询的结果集绑定到任何的ASP.NET控件。
For example, we could declare an <gridview> control in a .aspx page like so:<br><br> 例如,我可以在.aspx页面像这样声明一个<gridview>控件:</gridview></gridview>
I could then databind the result of the LINQ to SQL query we wrote before to the GridView like so:
然后我可以像下面这样写LINQ to SQL的查询来绑定查询结果到gridview上:
This will then generate a page that looks like below:
然后它就就会生成一个如下的页面:
Shaping our Query Results
格式化查询结果
Right now when we are evaluating our product query, we are retrieving by default all of the column data needed to populate the Product entity classes.
下面,当我们想评估我们的产品查询,默认情况下我们查出所有的在Product实体类中存在的列。
For example, this query to retrieve products:
例如用下面这个查询来检索产品:
Results in all of this data being returned:
返回的所有数据结果集:
Often we only want to return a subset of the data about each product. We can use the new data shaping features that LINQ and the new C# and VB compilers support to indicate that we only want a subset of the data by modifying our LINQ to SQL querylike so:
通常我们只想返回每个产品的所有属性集合的一个子集。这样的话,我们就可以用C#和VB编译器和LINQ支持的新的数据格式化特性(data shaping features)来声明我们只想返回属性集合的一个子集,像下面这样来修改代码:
This will result in only this data subset being returned from our database (as seen via our debug visualizer):
这将使得仅仅从数据库中返回这个子集(如在调试器中所示):
What is cool about LINQ to SQL is that I can take full advantage of my data model class associationswhen shaping my data. This enables me to express really useful (and very efficient) data queries. For example, the below query retrieves the ID and Name from the Product entity, the total number of orders that have been made for the Product, and then sums up the total revenue value of each of the Product's orders:
LINQ to SQL酷的是,在格式化数据时,我可以充分利用我的数据模型的关系。这使得我可以表达真正有用(而且非常高效)的数据查询。例如,如下的这个查询检索Product实体的ID和Name,该产品的订单总数,然后将每个产品的订单的利润加了起来。
The expression to the right of the "Revenue" property above is an example of using the "Sum" extension method provided by LINQ. It takes a Lambda expression that returns the value of each product order item as an argument.
上面这个表达式中,Revenue右边的属性是使用LINQ 提供的"Sum"扩展方法(extension method)。它使用了返回了每个产品的订单欺项作为参数的Lambda表达式(Lambda expression)。
LINQ to SQL is smart and is able to convert the above LINQ expression to the below SQL when it is evaluated (as seen via our debug visualizer):
LINQ to SQL非常智能,并且能够在求值时将以上的LINQ 表达式转换为如下的SQL语句:
The above SQL causes all of the NumOrders and Revenue value computations to be done inside the SQL server, and results in only the below data being retrieved from the database (making it really fast):
以上的SQL语句使得所有的订单计算和产品利润计算在SQL server中完成,并且生成了从数据库中返回仅有如下结果集的数据(这使得它运行更加快):
We can then databind the result sequence against our GridView control to generate pretty UI:
然后我们可以将结果序列绑定到我们的GridView控件来生成一个漂亮的UI:
BTW - in case you were wondering, you do get full intellisense within VS 2008 when writing these types of LINQ shaping queries:
顺便提一下--为了防止你疑惑,在Vs2008中,写这些LINQ 格式的查询时会有完全的智能提示:
In the example above I'm declaring an anonymous type that uses object initialization to shape and define the result structure. What is really cool is that VS 2008 provides full intellisense, compilation checking, and refactoring supportwhen working against these anonymous result sequences as well:
在上面的例子中,我声明了一个使用了对象初始化(object initialization )的匿名类型(anonymous type)来格式化和定义结果结构。真正酷的是,Vs2008提供了完全的智能感知,编译时检查,和当对这个匿名结果序列进行重构时的支持:
Paging our Query Results
对查询结果分页
One of the common needs in web scenarios is to be able to efficiently build data paging UI. LINQ provides built-in support for two extension methods that make this both easy andefficient- the Skip() and Take() methods.
在Web开发时,最常见的一个需求就是能够高效地建立数据分页的UI。LINQ 提供了两个内置的扩展方法,它使得分页不但简便,而且高效--Skip()和Take()方法。
We can use the Skip() and Take() methods below to indicate that we only want to return 10 product objects - starting at an initial product row that we specify as a parameter argument:
我们可以用下面的Skip()和Take()方法来声明我们只想从数据库中返回10条产品对象--从初始的产品记录开始(此处我们作为了一个参数)
Note above how Idid notadd the Skip() and Take() operator on the initial products query declaration - but instead added it later to the query (when binding it to my GridView datasource). People often ask me "but doesn't this mean that the query first grabs all the data from the database and then does the paging in the middle tier (which is bad)?" No. The reason is that LINQ uses a deferred execution model - which means that the query doesn't actually execute until you try and iterate over the results.
注意上面我为何没在初始的产品查询声明时用Skip()和Take()操作符--而是稍后将它加到了查询中(当将数据绑定到GridView的DataSource时)。人们经常问我,“但是这不意味着该查询首先从数据库中查询出所有记录然后在中层层进行分页(这是不好的)?”,答案是否定的。原因就是LINQ用的是一个“延迟执行”的执行模式--它意味着直到当你试图遍历结果集时它才会执行。
One of the benefits of this deferred execution model is that it enables you to nicely compose queries across multiple codestatements (which improves code readability). It also enables you to compose queries out of other queries - which enables some very flexible query composition and re-use scenarios.
Once I have the BindProduct() method defined above, I can write the code below in my page to retrieve the starting index from the querystring and cause the products to be paged and displayed in the gridview:
This will then give us a products page, filtered to list only those products with more than 5 orders, showing dynamically computed product data,and which is pageable via a querystring argument:
这然后就会展示给我们一个产品页,仅仅显示了超过5条订单产品,显示动态计算出来的产品数据,而且它是可以通过Querystring参数进行分页:
Note: When working against SQL 2005, LINQ to SQL will use the ROW_NUMBER() SQL function to perform all of the data paging logic in the database. This ensures that only the 10 rows of data we want in the current page view are returned from the database when we execute the above code:
注意:当使用SQL 2005时,LINQ to SQL将会在数据库中使用ROW_NUMBER()这个SQL函数来执行分页逻辑。这保证了当我们执行以上的代码时,从数据库中仅返回10条在当前页面上显示的我们需要显示的的数据:
This makes it efficient and easy to page over large data sequences.
这使得对大的数据表进行分页变得高效和容易。
Summary
总结
Hopefully the above walkthrough provides a good overview of some of the cool data query opportunities that LINQ to SQL provides. To learn more about LINQ expressions and the new language syntax supported by the C# and VB compilers with VS 2008, please read these earlier posts of mine:
希望以上的代码给你提供了一些LINQ to SQL提供的很酷的数据查询的概述。若想更多地了解LINQ 表达式和VS2005中C#及VB编译器支持的语法,请阅读我前期的一些帖子:
- Automatic Properties, Object Initializer and Collection Initializers
- Extension Methods
- Lambda Expressions
- Query Syntax
- Anonymous Types
In my next post in this LINQ to SQL series I'll cover howwe cancleanly add validation logic to our data model classes, and demonstrate how we can use it to encapsulate business logic that executes every time we update, insert, or delete our data. I'll then cover more advanced lazy and eager loading query scenarios, how to use the new <linqdatasource> control to support declarative databinding of ASP.NET controls, optimistic concurrency error resolution, and more.<br></linqdatasource>
在本系列的下一篇帖子中,我将讲述一下如何向我们的数据模型中添加一个清晰的验证逻辑,并且讲述如何用它来减少每次我们进行更新,插入或删除数据时都会执行的业务验证。届时我会更深入地讲解延迟和即时加载的情景,如何使用<linadatasource>控件来支持显示的绑定ASP.NEt控件,优化并发冲突错误的解决方案,以及其他的一些知识。<br><br> Hope this helps,<br> 希望这些对你有所帮助。</linadatasource>
Scott