LINQ在VB中是如何对Dataset工作的
[原文作者]:Jonathan Aneja
[原文链接]:How LINQ to Dataset works in VB
posted on 2008-10-28 14:10:20 by VBCTI 评论(5) 阅读(2428)
|
随笔 - 89, 评论 - 163, 引用 - 33 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
LINQ在VB中是如何对Dataset工作的[原文作者]:Jonathan Aneja [原文链接]:How LINQ to Dataset works in VB LINQ的核心要求任何数据源能够被查询,这基本上意味着它必须实现IEnumerable接口(实际情况要更复杂一点,详细的说明请参见Visual Basic 9.0语言规范之11.21.2一节,<Visual Basic 9.0 Language Specification >)。现在,当使用LINQ对Dataset进行工作时我们就有了一个问题:DataTable没有实现IEnumerable,那么我们该如何来对它进行查询?
如我们昨天<yesterday>所见,Visual Studio 2008中包含有一个名为 System.Data.DataSetExtensions.dll的assembly,它定义了一个叫做AsEnumberable()的扩展方法<extension method>。这里是这个方法看上去的样子:
<Extension()> _
Public Function AsEnumerable(source As DataTable) As EnumerableRowCollection(Of DataRow)
基本上,该方法接收一个DataTable,然后返回实现了IEnumberable(Of T)某个东西,然后LINQ就可以用它来构造标准的查询操作符了。因此,你需要做的是 import System.Data(默认情况下项目模板就会把这个做好),然后你就可以通过调用AsEnumberable()来使用LINQ对一个Dataset进行查询了:
Dim customers = TestDS.Tables("Customers")
Dim franceCustomers = From cust In customers.AsEnumerable() _
Where cust!Country = "France" _
Select cust
现在,关于LINQ在VB中的工作方式的有趣事情之一是:你其实并不真正需要为上面的代码去显式的调用AsEnumberable()以通过编译。即使DataTable没有实现IEnumerable,编译器会通过“自动查找某些可以将之转换成某种可被查询的东西的方法”来帮助你解决这个问题。当VB编译器碰到一个要对某个未实现IEnumberable、IEnumerable(Of T)、IQueryable、或IQueryable(Of T)的类型进行工作的LINQ查询时,它会依次执行以下工作:
1. 检查该类型上是否有一个标准的Select方法可用;
2. 检查该类型上是否有一个名为AsQueryable的实例方法,该方法应能返回一个可查询的类型;
3. 检查该类型上是否有一个在作用期内的扩展方法AsQueryable,该方法应能返回一个可查询的类型;
4. 检查该类型上是否有一个名为AsEnumerable的实例方法,该方法应能返回一个可查询的类型;
5. 检查该类型上是否有一个在作用期内的扩展方法AsEnumerable,该方法应能返回一个可查询的类型;
如果编译器在任一步中找到了一个匹配的方法,它就会插入一个对该方法的调用。当System.Data这个namespace被Import了以后,编译器在第5步为DataTable找到了一个匹配的,然后为你插入对AsEnumerable的调用。结果,你就可以象这个从101 LINQ Samples(http://msdn.microsoft.com/en-us/vbasic/bb688088.aspx)中拿来的示例那样编写对DataSet操作的LINQ:
Dim customers = TestDS.Tables("Customers")
Dim franceCustomers = From cust In customers _
Where cust!Country = "France" _
Select cust
这里的意思,是你可以通过提供一个能够返回某种可查询的东西的AsEnumerable扩展方法来使得你的类型可以被LINQ使用。
注意,对于强类型的Dataset,你不需要去调用AsEnumerable,因为它们继承自TypedTableBase(Of T),而后者则实现了IEnumerable。这里VS2008中的一个新类型;在VS2005中,Dataset Designer将会生成从DataTable继承的代码,然后自己去显示的实现IEnumerable。
posted on 2008-10-28 14:10:20 by VBCTI 评论(5) 阅读(2428) 从 SQL 到 LINQ, 第7部分: 合并, TOP, 子查询 (Bill Horst)[原文作者]:Bill Horst
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
SQL |
|
SELECT CustomerID ID FROM CustomerTable UNION SELECT OrderID ID From OrderTable
|
|
VB |
|
(From Contact In CustomerTable _ Select ID = Contact.CustomerID).Union(From Shipment In OrderTable _ Select ID = Shipment.OrderID)
|
TOP
SQL的TOP运算符返回一个查询结果的前n行. VB LINQ中的Take子句可以达到同样效果. 下面的例子详细描述了Take的功能, 同时使用了一些其他相关的子句.
|
SQL |
|
SELECT TOP 10 * FROM CustomerTable ORDER BY CustomerID
|
|
VB |
|
From Contact In CustomerTable Order By Contact.CustomerID Take 10
|
Take/Skip/While
Take子句作用于位于它前面的子句, 并指定一个表示要 ”取” 或返回多少条结果的数字. 查询结果中其他的记录会被丢弃.
Skip子句指定了一个数字, 表示要忽略查询结果中 “前” 多少条记录. 当前面子句的结果被传递给Skip子句后, 它只返回除了前n条记录外的其他结果.
Take While子句指定一个条件, 并从一个查询结果的开头获取记录, 直到这个条件为False.
Skip While子句指定一个条件, 并从一个查询结果的开头获取记录, 它会忽略前面的记录, 直到这个条件为False.
举几个具体的例子, 下面的几个查询返回如下的结果:
|
VB |
|
Dim digits = New Integer() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Dim AllDigits = From int In digits
|
|
返回结果: 0 3 6 9 1 4 7 2 5 8
|
|
SKIP
Dim SkipFirstTwo = From int In digits Skip 2
|
|
返回结果: 2 5 8 3 6 9 4 7
|
|
TAKE
Dim TakeFirstTwo = From int In digits Take 2
|
|
返回结果: 0 1
|
|
SKIP and TAKE together
Dim SkipTwoTakeFive = From int In digits Skip 2 Take 5
|
|
返回结果: 2 5 3 6 4
|
|
SKIP WHILE
Dim SkipUntilFour = From int In digits Skip While int Mod 5 <> 4
|
|
返回结果: 4 7 5 8 6 9
|
|
TAKE WHILE
Dim TakeUntilThree = From int In digits _ Take While int = 0 OrElse int Mod 3 <> 0
|
|
返回结果: 0 2 1
|
子查询
SQL的SELECT语句可以包含子查询, 就是指一个查询使用了另一个查询的结果. 在VB LINQ中, 子查询可以出现在任何允许使用LINQ表达式的地方, 像SQL子查询一样, 你可以使用括号来避免语法中的歧义.
|
SQL |
|
SELECT OrderID, OrderDate FROM OrderTable WHERE CustomerID = (SELECT CustomerID FROM CustomerTable WHERE City = “Seattle”)
|
|
VB |
|
From Shipment In OrderTable _ Where (From Contact In CustomerTable _ Where Contact.City = “Seattle” _ Select Contact.CustomerID).Contains(Shipment.CustomerID) _ Select Shipment.OrderID, Shipment.OrderDate
|
还要注意的是, 因为一个查询返回的是IEnumerable, 所以你还可以对查询结果进行查询:
|
VB |
|
Dim SeattleOrders = From Contact In CustomerTable _ Join Shipment In OrderTable _ On Contact.CustomerID Equals Shipment.CustomerID _ Where Contact.City = “Seattle”
Dim FilteredOrders = From Shipment In SeattleOrders _ Select Shipment.OrderID, Shipment.OrderDate
|
我很有兴趣知道你们对主题的看法. 下次, 我会仔细地讨论一下LEFT/RIGHT/FULL OUTER JOIN.
- Bill Horst, VB IDE Test
posted on 2008-01-28 13:13:00 by VBCTI 评论(2) 阅读(6041)
[原文作者]:Bill Horst
[原文链接]:Converting SQL to LINQ, Part 6: Joins (Bill Horst)
本文假设您已阅读了本系列中此前发表的文章:
从SQL 到 LINQ, Part 1: 基础(Bill Horst)
从SQL 到 LINQ, Part 2: FROM 和 SELECT(Bill Horst)
Converting SQL to LINQ, Part 3: DISTINCT, WHERE, ORDER BY and Operators
Converting SQL to LINQ, Part 4: Functions
Converting SQL to LINQ, Part 5: GROUP BY and HAVING
本文将讨论一下交叉联接Cross Join, 内联接Inner Join, 自然联接Natural Join 和外(左/右)联接 Outer (Left/Right) Join.
联接
在一个SQL SELECT语句中查询一个以上的数据集(例如:表)是比较常见的. 把多个表中的信息集中在一起就叫做联接, 而在SQL和LINQ中有好几种不同的联接.
交叉联接
最简单的连接是交叉联接, 又叫笛卡尔积, 是针对两个数据集合的多对多的联接, 一个数据集中的每一条记录与另一个数据集中的每条记录都进行连接. 在一个SQL SELECT语句中, 要实现交叉联接只要在FROM子句中指定一个以上的表就可以了. 在VB LINQ中, 可以用相同的方式实现, 如下所示:
|
SQL |
|
SELECT CustomerTable.Name, OrderTable.OrderDate FROM CustomerTable, OrderTable |
|
VB |
|
From Contact In CustomerTable, Shipment In OrderTable _ Select Contact.Name, Shipment.OrderDate |
内联接
内联接是一对一的联接, 一个数据集中的记录根据两个数据集中特定的相同字段与另一个数据集中的记录做匹配. 在一个SQL SELECT语句中, 第二个数据集在INNER JOIN子句中指定, 匹配条件在ON子句中指定. 与此类似, 在VB LINQ联接中, 第二个数据集在Join中指定, 而On子句则用来指定Equals运算符与哪个字段相匹配.
|
SQL |
|
SELECT Contact.Name, Shipment.OrderID FROM CustomerTable Contact INNER JOIN OrderTable Shipment ON Contact.CustomerID = Shipment.CustomerID AND Contact.Zip = Shipment.ShippingZip |
|
VB |
|
From Contact In CustomerTable Join Shipment In OrderTable _ On Contact.CustomerID Equals Shipment.CustomerID _ And Contact.Zip Equals Shipment.ShippingZip _ Select Contact.Name, Shipment.OrderID |
上面的例子是一个对等联接, 意味着用一个相等运算符联接两个表的信息. 这是On子句中唯一允许使用的运算符, 所以要想实现其他的联接运算符(例如:小于), 你需要使用一个带Where子句的交叉联接.
|
SQL |
|
SELECT Contact.Name, Shipment.OrderID FROM CustomerTable Contact INNER JOIN OrderTable Shipment ON Contact.CustomerID < Shipment.CustomerID |
|
VB |
|
From Contact In CustomerTable, Shipment In OrderTable _ Where Contact.CustomerID < Shipment.CustomerID Select Contact.Name, Shipment.OrderID |
自然联接
自然联接也是一对一的联接, 在自然联接中一个数据集中的记录依据两个数据集中所有的相同字段(具有相同的名称)与另一个表中的记录做匹配. 在一个SQL SELECT语句中, 第二个数据集可以在NATURAL JOIN子句中指定, 而用来联接的匹配条件是隐含的. 在VB LINQ中没有和自然联接直接对应的语法, 所以要实现它的最好方法是创建一个内联接并在On子句中手动指定所有相同字段的相等关系. 与SQL的自然联接相比, 这显得有点冗长, 但理解起来比较容易.
|
SQL |
|
SELECT * FROM CustomerTable NATURAL JOIN OrderTable |
|
VB |
|
From Contact In CustomerTable _ Join Shipment In OrderTable _ On Contact.CustomerID Equals Shipment.CustomerID _ |
外(左/右)联接
外联接(也被称为左联接或右联接), 是一种一对多的联接, 一个数据集中的每条记录根据两个数据集的相同字段可以与另一个数据集中的多条记录相匹配. 在一个SQL SELECT语句中, 第二个数据集在LEFT JOIN或RIGHT JOIN子句中指定, 用来联接两个数据集的匹配条件在ON 子句中指定. 在LEFT JOIN中, 第一个(左)数据集中的每条记录根据匹配条件与第二个表中所有满足匹配条件的记录相联接. 第一个数据集中的所有记录都会出现在结果集中, 不论第二个数据集中有没有与之匹配的记录. 这与RIGHT JOIN相反, 在外联接中所有第二个(右)数据集中的记录都会出现在结果集中, 并尽可能与第一个数据集中的任何匹配的记录相联接.
在VB LINQ中, 与外连接最相似的结构是分组联接. 在分组联接中, Group Join子句指定了第二个数据集, 并在On子句中提供匹配条件, 这与本文前面描述的联接(内联接)很相像. VB LINQ中还有一个Into子句, 它可以用来指定对每个分组执行什么样的集合运算, 就像是在一个像前面Group Join那样的子句中.
与SQL LEFT JOIN类似, 分组连接中第一个数据集的每个成员, 与第二个数据集中所有和它相匹配的记录相联接. 再次提醒一下, 如果第二个数据集中没有任何记录与第一个数据集中的某条记录相匹配, 这条记录仍然会出现在结果集中.
|
SQL |
|
SELECT CustomerTable.Name, SUM(OrderTable.Cost) Sum FROM CustomerTable LEFT JOIN OrderTable ON CustomerTable.CustomerID = OrderTable.CustomerID GROUP BY CustomerTable.Name |
|
VB |
|
From Contact In CustomerTable _ Group Join Shipment In OrderTable _ On Contact.CustomerID Equals Shipment.CustomerID _ Into Sum(Shipment.Cost) _ Select Contact.Name, Sum |
实现RIGHT JOIN的最好方式是利用这个Group Join子句, 但需要颠倒其中的表(把后一个表作为第一个).
一个比较常见的情况是, 需要使用外联接但不需要进行集合运算. 像上面的示例那样使用Group关键字, 会导致结果被分为一连串大小不等的分组, 下面这个例子可能是VB LINQ中与不需要集合运算的外联接最类似的语法了.
|
SQL |
|
SELECT * FROM CustomerTable Contact LEFT JOIN OrderTable Shipment ON Contact.CustomerID = Shipment.CustomerID |
|
VB |
|
From Contact In CustomerTable _ Group Join Shipment In OrderTable _ On Contact.CustomerID Equals Shipment.CustomerID _ Into Group |
这些分组联接的例子可能没有涵盖你可能会遇到的LEFT JOIN 和 RIGHT JOIN 的所有情况, 但相信它们会给你一个创建与现有SQL查询相对应的LINQ查询的基本思路.
下个星期, 我打算做一个”百宝袋”, 主题包括合并(UNION), TOP 和子查询.
如果你有任何其他的SQL SELECT语句想要转换到LINQ, 请为本文添加一个关于它回复.
- Bill Horst, VB IDE 测试
posted on 2008-01-28 13:12:00 by VBCTI 评论(2) 阅读(4866)
[原文作者]:Bill Horst
[原文地址]:Converting SQL to LINQ, Part 5: GROUP BY and HAVING (Bill Horst)
本文假定您已阅读过本系列中此前发表的文章:
从SQL 到 LINQ, Part 1: 基础(Bill Horst)
从SQL 到 LINQ, Part 2: FROM 和 SELECT(Bill Horst)
Converting SQL to LINQ, Part 3: DISTINCT, WHERE, ORDER BY and Operators
Converting SQL to LINQ, Part 4: Functions
本文将讨论GROUP BY和HAVING子句.
GROUP BY
一个SQL GROUP BY 子句使你能够依据特定的字段把记录分组, 从而可以一次处理整个分组. 一个LINQ语句也可以包含一个Group By子句, 但语法有所不同. 下面是一个不正规 (也不完整) 的语法表达式:
|
VB Group By |
|
Group [{optional list of fields}] By {list of fields} _ Into {list of aggregate expressions}
|
在这个语法中列出来的所有表达式都可以有别名, 并且当一个标识不能被确定时必须使用别名. 一般说来, 子句首先是一个”Group By”, 其后有一个用来分组的字段的列表; 接着是一个 ”Into”, 其后是要进行集合计算的集合表达式. 例如, 下面的查询计算发送到每个邮政编码的总运输费用和平均运输费用:
|
VB |
|
From Shipment In OrderTable _ Group By Shipment.ShippingZip _ Into Total = Sum(Shipment.Cost), Average(Shipment.Cost) |
这个查询为数据表中存在的每个邮政编码返回3个值: 邮政编码, 运输费用总计和平均运输费用.
可选地, 在"Group” 和 "By” 关键字之间可以指定字段来减少某些字段中包含的信息. 这可以被看作是一个内置的, 在Into子句之前的Select子句:
|
VB |
|
From Shipment In OrderTable _ Group OrderCost = Shipment.Cost By Shipment.ShippingZip _ Into Total = Sum(OrderCost), Average(OrderCost) |
作为对集合表达式的补充, Into子句也可以包含 “Group” 关键字, 它的作用是使分组中的每个记录成为一个数组成员. 下面这个查询为数据中存在的每个邮政编码和订货日期的组合返回两组值, 邮政编码和订货日期, 加上一个包含分组中所有记录的数组.
|
VB |
|
From Shipment In OrderTable _ Group By Zip = Shipment.ShippingZip, Shipment.OrderDate _ Into Group |
如果"Group” 和" By” 之间没有指明字段, 如上所示, 则返回的数组中包含所有字段. 下面这个查询为数据中存在的每个邮政编码和订货日期的组合, 返回分组中每条记录的邮政编码和订货日期, 以及ID和支出两个字段组成的数组.
|
VB |
|
From Shipment In OrderTable _ Group ID = Shipment.OrderID, Shipment.Cost By _ Zip = Shipment.ShippingZip, Shipment.OrderDate _ Into Group |
因为语法确实很复杂, 我已给出了好几个例子, 现在我们开始看一下如何转换各种包含GROUP BY 子句的SQL语句到VB. 下面是一个例子:
|
SQL |
|
SELECT OrderDate Date_Of_Order, SUM(Cost) Daily_Total FROM OrderTable GROUP BY Date_Of_Order
|
|
VB |
|
From Shipment In OrderTable _ Group By Date_Of_Order = Shipment.OrderDate _ Into Daily_Total = Sum(Shipment.Cost)
|
Having
Having 是另一个可以在查询结果中指定分组条件的SQL子句. VB中没有类似的子句, 所以用VB LINQ实现它的最好的方式是在Group By子句后使用一个Where子句, 如下所示:
|
SQL |
|
SELECT OrderDate Date_Of_Order, SUM(Cost) Total_Cost FROM OrderTable GROUP BY Date_Of_Order HAVING SUM(Cost) > 1000
|
|
VB |
|
From Shipment In OrderTable _ Group By Date_Of_Order = Shipment.OrderDate _ Into Total_Cost = Sum(Shipment.Cost) Where Total_Cost > 1000
|
在下一篇文章中, 我打算讨论各种各样的联接.
- Bill Horst, VB IDE Test
posted on 2008-01-28 13:10:00 by VBCTI 评论(1) 阅读(5551)
[原文作者]: Bill Horst
[原文链接]: Converting SQL to LINQ, Part 4: Functions (Bill Horst)
在看这篇文章之前,我假定你已经读过了:
从SQL到LINQ,Part 3:DISTINCT, WHERE, ORDER BY 和 操作符
这篇文章讨论的是标量函数(scalar functions)和聚合函数(aggregate functions)。
函数
SQL的SELECT子句经常会涉及到函数,包含标量函数和聚合函数。一个聚合函数针对的是select出来的一组记录,而标量函数针对的则是其中的个体。我们可以利用VB LINQ表达式实现这两种操作-但是,方法有所不同。
标量函数(Scalar Functions)
标量函数不论参数如何操作的都是单个记录。他们可以在SQL查询的不同位置出现,比如SELCET子句。虽然标量函数会根据系统的不同而有所不同,但是我们总可以使用类似的VB方法在LINQ语句中进行模拟。如果在LINQ的Select子句中使用标量函数,你可能也需要指定一个别名(FirstThreeLetters, CurrentTime)。
|
SQL |
|
SELECT LEFT(ItemName, 3) FirstThreeLetters, NOW() CurrentTime FROM OrderTable |
|
VB |
|
From Shipment In OrderTable _ Select FirstThreeLetters = Left(Shipment.ItemName, 3), CurrentTime = Now |
在上面的例子中,Left和Now是VB已有的方法(在Microsoft.VisualBasic.dll里定义)。其实大多数SQL支持的标量方法都可以在VB中找到,即使你想调用的方法在VB里还不存在,你可以自己去定义它。但是,用户自定义的方法不能在数据库查询中使用,在运行时系统会抛出异常。在下面的例子中,MyFunction就是一个自定义的方法。
|
VB |
|
From Shipment In OrderTable _ Select MyFunction(Shipment.Cost, Shipment.ShippingZip) |
聚合函数(Aggregate Functions)
聚合函数操作的是整个集合,并返回一个值。在SQL语句中,他们可以出现在SLECT子句里。而在LINQ中,情况有所不同。
一个VB LINQ表达式通常由From子句开始,但是,也可以是Aggregate子句。Aggregate子句和From子句语法一样,一个由Aggregate开始的子句必须以Into子句结束。Into子句是一组带别名的,由逗号分割的,集合函数调用的列表(a comma-delimited list of Aggregate function calls, with aliases that can accompany them)。下面的例子展示了在SQL的SELECT语句中如何使用集合函数,以及其在LINQ中的等价操作。
|
SQL |
|
SELECT SUM(Cost) TotalCost, COUNT(*) FROM OrderTable WHERE OrderDate > “Sept-29-2007” |
|
VB |
|
Aggregate Shipment In OrderTable _ Where Shipment.OrderDate > #9/29/2007# _ Into TotalCost = Sum(Shipment.Cost), Count() |
下次,我们讨论GROUP BY 和 HAVING。
posted on 2008-01-14 12:22:00 by VBCTI 评论(2) 阅读(5264)
[原文作者]: Bill Horst
[原文链接]: Converting SQL to LINQ, Part 3: DISTINCT, WHERE, ORDER BY and Operators (Bill Horst)
在看这篇文章之前,我假定你已经读过了:
继续我们的话题,这次我将涉及的主题是DISTINCT, WHERE 和 ORDER BY相关的内容。
DISTINCT
SQL的SLECT语句可以指定DISTINCT标识符以去除所有重复的记录。在LINQ表达式里,Distinct不是从属与Select的标识符,而是一个单独的子句-这意味着Distinct可以出现在任意子句后面,并返回去除重复记录前面子句(在下面的例子里是Select)的结果。下面两个语句得到的是相同的结果:
|
SQL |
|
SELECT DISTINCT Name, Address FROM CustomerTable |
|
VB |
|
From Contact In CustomerTable _ Select Contact.Name, Contact.Address _ Distinct |
WHERE
和SQL非常相似,LINQ允许你使用Where子句根据一定的条件筛选记录。你可以使用任意合法的VB布尔表达式。
|
SQL |
|
SELECT * FROM CustomerTable WHERE State = “WA” |
|
VB |
|
From Contact In CustomerTable _ Where Contact.State = “WA” |
操作符
SQL的WHERE子句可以包含AND这样的操作符,LINQ也允许类似的用法。
|
SQL |
|
SELECT * FROM CustomerTable WHERE City = “Seattle” AND Zip = “98122” |
|
VB |
|
From Contact In CustomerTable _ Where Contact.City = “Seattle” And Contact.Zip = “98122” |
即使有些操作符不能完全等价,我们仍然可以模拟。例如BETWEEN:
|
SQL |
|
SELECT * FROM OrderTable WHERE OrderDate BETWEEN ‘Sept-22-2007’ AND ‘Sept-29-2007’ |
|
VB |
|
From Shipment In OrderTable _ Where (Shipment.OrderDate > #9/22/2007#) _ And (Shipment.OrderDate < #9/29/2007#) |
ORDER BY
LINQ也提供了类似SQL ORDER BY子句的表达式,它允许我们使用一个由逗号隔开的列表来指定得到结果的排序依据。我们可以使用任意合法的VB表达式,而并不一定要用Select出来的名字。
|
SQL |
|
SELECT * FROM CustomerTable ORDER BY Phone |
|
VB |
|
From Contact In CustomerTable _ Order By Contact.Phone |
ASC/DESC
SQL的ORDER BY子句可以使用ASC和DESC关键字来指定升序和降序。VB使用的对应的关键字是Ascending 和 Descending,如果没有指定,默认升序。
|
SQL |
|
SELECT * FROM CustomerTable ORDER BY Phone ASC, Name DESC |
|
VB |
|
From Contact In CustomerTable _ Order By Contact.Phone Ascending, Contact.Name Descending |
到目前为止,我们应该已经可以将基本的SQL查询写成LINQ代码。下一次,我会谈到函数-包含Scalar和Aggregate。
- Bill Horst, VB IDE Test
posted on 2008-01-03 17:21:00 by VBCTI 评论(4) 阅读(6571)
[原文作者]: Bill Horst
[原文链接]: Converting SQL to LINQ, Part 2: FROM and SELECT (Bill Horst)
在看这篇文章之前,我假定你已经读过了从SQL到LINQ,Part 1:基础。
为了让代码示例更清晰,我修改了下列名字:
· Customers -> CustomerTable
· Orders -> OrderTable
· cust -> Contact
· CustomerName -> ContactName
· ID -> ContactID
欢迎你们的任何反馈和建议,你们的意见可以使以后的文章更清晰更有用。
好,现在开始讨论具体的子句(clauses),我们将从最基础的FROM和SELECT开始。
FROM
SQL的SELECT语句由SELECT子句开始,并且紧跟着一个FROM子句。而VB查询表达式则由From子句(或者Aggregate子句,我们稍后讨论)开始。一个基本SQL的FROM子句指定了一个要操作的表,一个LINQ的From子句指定了一个我们要操作的对象(CustomerTable)。这个对象可以表示“已在内存中的”(“In-Memory”)数据:比如一个SQL表,或者XML信息。因为使用这样的数据比较简单,我的例子也采用了”In-Memory”的数据。除了这个数据对象,VB的From子句还包含了一个指定当前“行”(Contact)别名的标识符。
如果要选择所有的列,在SQL中我们需要使用”*”,而在VB中,我们不需要附加任何东西,From子句默认返回所有的内容。
|
SQL |
|
SELECT * FROM CustomerTable |
|
VB |
|
From Contact In CustomerTable |
FROM里的别名(alias)
SQL允许你在FROM子句中指定一个表的别名,LINQ同样允许我们这样做。
|
SQL |
|
SELECT Contact.CustomerID, Contact.Phone FROM CustomerTable Contact |
|
VB |
|
From Contact In CustomerTable Select Contact.CustomerID, Contact.Phone |
SELECT
SQL的SELECT语句由一个包含要select的内容的列表开始(Name, CustomerID)。 类似的,LINQ也允许你指定要select的内容,并将结果包装成一个匿名类型(anonymous type)返回。你指定的内容并不一定要是From子句指定对象的一部分,你可以指定任意合法的VB表达式(比如3+4)。如果成员的名字不能够被推断,你必须为其指定一个别名(见下面的“SELECT里的别名”)。
|
SQL |
|
SELECT Name, CustomerID FROM CustomerTable |
|
VB |
|
From Contact In CustomerTable Select Contact.Name, Contact.CustomerID |
SELECT里的别名
SQL允许SELCT子句的成员有别名(ContactName, ContactID),我们可以在查询语句的其它子句中使用这些别名。LINQ也允许别名,并且你可以在所有使用这个查询结果的代码中使用它们。
|
SQL |
|
SELECT Name ContactName, CustomerID ContactID FROM CustomerTable |
|
VB |
|
From Contact In CustomerTable Select ContactName = Contact.Name, ContactID = Contact.CustomerID |
下次我打算讲到DISTINCT, WHERE, ORDER BY 和运算符。
- Bill Horst, VB IDE Test
posted on 2007-12-26 14:26:00 by VBCTI 评论(3) 阅读(4760)
[原文作者]: Bill Horst
[原文链接]: Converting SQL to LINQ, Part 1: The Basics
你可能已经知道了,VB的LINQ指令允许使用类SQL语法的查询。LINQ的语法并不和SQL的语法完全一致,所以如果你现在已经在用SQL或者熟悉SQL查询的话,你可能会想把已经存在的SQL查询转化为LINQ。
这篇文章就是“从SQL到LINQ”系列的第一篇。在这篇文章里,我想让大家对SQL和LINQ的区别有一个基本的理解,下次我们会涉及到具体的语言架构。
假定
在接下来的例子, SQL代码会涉及到两个table:Customers和Orders,VB代码会用到与之同名的两个对象,他们的类型分别是IEnumerable(Of Customer)和IEnumerable(Of Order)。我还会用到两个类,同样是Customer和Order,如下:
|
Class Customer Public CustomerID As Integer Public Name As String Public Phone As String Public Address As String Public Zip As String End Class Class Order Public OrderID As Integer Public CustomerID As Integer Public Cost As Single Public Phone As String Public OrderDate As DateTime Public ShippingZip As String Public ItemName As String End Class |
基本语法
LINQ支持SQL SELECT语句,而不支持其他的,比如CREATE, INSERT, UPDATE 和 DELETE。你可以认为SQL SELECT语句的基本语法是一系列的“子句”(clauses),其中的第一个是SELECT子句。
|
sqlSelectClause [ sqlClause1 [ sqlClause2 [ ... ] ] ] |
SQL的语法可能根据不同的版本有所差异,下面是一个例子:
|
SQL |
|
SELECT Name CustomerName, CustomerID ID FROM Customers ORDER BY ID |
VB LINQ表达式的基本语法也是一系列的子句,不同的是第一个是From子句(或者Aggregate子句,我们稍后会讨论)。
|
linqFromClause [ linqClause1 [ linqClause2 [ ... ] ] ] |
比如:
|
VB |
|
From cust In Customers _ Select CustomerName = cust.Name, ID = cust.CustomerID _ Order By ID |
我刚才用了“VB LINQ表达式”的说法是因为前面的“LINQ查询”不是一个完整的语句。虽然SQL语句可以单独出现,但是LINQ查询在语法上和表达式“3 * 4”一样 - 它不是一个完整的语句,所以我们要使它完整。一个VB的完整的LINQ查询的语句看起来像这样:
|
VB |
|
Dim SortedCustomers = From cust In Customers _ Select CustomerName = cust.Name, ID = cust.CustomerID _ Order By ID |
从概念上说,LINQ查询的每个子句操作的都是IEnumerable(Of T)类型并且返回的也是IEnumerable(Of T)类型”(其中的两个T并不一定要相同)。查询子句和SQL子句是基本类似的(比如SELECT, ORDER BY),所以你可以一个子句一个子句地将SQL查询转化成LINQ。在上面的例子里,这些子句出现的顺序稍有不同,而且有些语法上的差异,但是你可以看到,他们非常类似。
还要注意的一点是,SQL语法允许在子句间直接换行,而在VB里,换行需要在每行最后加上下划线(_)去告诉编译器下一行仍然是当前的表达式。
这篇文章只是一个泛泛的说明,但我会在以后讲到更为具体的内容。我打算涉及以下条目:
- Bill Horst, VB IDE Test
posted on 2007-12-21 14:09:00 by VBCTI 评论(7) 阅读(5738)
Powered by: Joycode.MVC引擎 0.5.2.0
Copyright © 分享VB,畅“享”VB