随笔 - 89, 评论 - 163, 引用 - 33

导航

关于

标签

每月存档

最新留言

广告

从 SQL 到 LINQ, 第7部分: 合并, TOP, 子查询 (Bill Horst)

[原文作者]Bill Horst
[原文地址]Converting SQL to LINQ, Part 7: UNION, TOP, Subqueries (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

Converting SQL to LINQ, Part 6: Joins

 

    本文中我们将讨论一下合并, TOP 和子查询. 下个星期, 我打算更深入地介绍一下LEFT, RIGHT FULL OUTER JOIN. 如果你想了解关于转换SQLLINQ的其他问题, 请回复本文.

 

合并(UNION)

 

SQL, 一个UNION子句合并两个SELECT查询结果为一个数据集. VB LINQ, 可以通过在一个查询中调用Union方法, 并把第二个查询传递给这个方法可以得到相同的结果. Intersect方法也一样可以这样调用, 它返回的是两个查询的交集. Except方法返回的结果只包括那些在第一个查询中出现但不在第二个查询中出现记录.

 

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

 

SQLTOP运算符返回一个查询结果的前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

 

 

子查询

 

    SQLSELECT语句可以包含子查询, 就是指一个查询使用了另一个查询的结果. 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)

从 SQL 到 LINQ, 第6部分: 联接 (Bill Horst)

[原文作者]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语句中查询一个以上的数据集(例如:)是比较常见的. 把多个表中的信息集中在一起就叫做联接, 而在SQLLINQ中有好几种不同的联接.

 

交叉联接

 

最简单的连接是交叉联接, 又叫笛卡尔积, 是针对两个数据集合的多对多的联接, 一个数据集中的每一条记录与另一个数据集中的每条记录都进行连接. 在一个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 _
And Contact.Phone Equals Shipment.Phone

 

 

(/)联接

 

外联接(也被称为左联接或右联接), 是一种一对多的联接, 一个数据集中的每条记录根据两个数据集的相同字段可以与另一个数据集中的多条记录相匹配. 在一个SQL SELECT语句中, 第二个数据集在LEFT JOINRIGHT 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) 阅读(4867)

从SQL 到LINQ, 第5部分: GROUP BY 和 HAVING (Bill Horst)

[原文作者]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 BYHAVING子句.

 

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) 阅读(5553)

Visual Basic 2008发布了!

[原文作者]Amanda Silver

[原文链接]Visual Basic 2008 Ships!!! (Amanda Silver)

 

太好了!今天我们终于发布了Visual Studio 2008, 就是以前所说的Orcas,也是作为一个没有ASCII表示ASCII representation)的符号。我们走过了漫长的路,但这是一件伟大的事情!Soma在自己的博客中高屋建瓴地介绍了VS2008的很多足以让每一个开发员和IT主管都很向往的旗舰功能,不过在这篇文章中我们主要讨论Visual Basic

对于各个行业的Visual Basic用户来说,这是一个意义重大的发布,因为我们第一次把查询表达式(query expressions)和XML作为第一类数据类型。这不但使Visual Basic在开发以数据为中心的应用程序时更加有效,而且让VB程序员成为很多喜爱尝试新领域的科技高手(alpha-geek)羡慕的对象。如果你想体验一下,就去下载一个Visual Basic Express, 它拥有以上谈到的所有功能。

因为query,整个.NET Framework变成了一个可查询的数据源。现在你可以查询.NET Framework中任何有效的东西——注册表、文件系统、进程等等。例如:下面的代码查询运行的进程,返回线程数大于10的进程,并按线程数排序:

        Dim query = From proc In Process.GetProcesses _

            Let ThreadCount = proc.Threads.Count _

            Where ThreadCount > 10 _

            Order By ThreadCount _

                        Select proc.ProcessName, proc.Id, ThreadCount

有了LINQSQL的对象关系映射框架,我们就可以把SQL数据库当作由Framework暴露的对象集合来查询。下面的查询找到所有被停止的产品,然后按种类分组,并且找出每种产品的库存总量

        Dim db As New NorthwindDataContext(My.Settings.NORTHWNDConnectionString)

        Dim query = From prod In db.Products _

                    Where prod.Discontinued = True _

                    Group By prod.CategoryID _

                    Into Count(), NumInStock = Sum(prod.UnitsInStock) _

                    Join cat In db.Categories On cat.CategoryID Equals CategoryID _

                                        Select cat.CategoryName, Count, NumInStock

 

我可以从上面这个查询得到即时反馈,再也不用写冗长的SQL查询字符串了。

智能提示:

语法检查:

 结构检查:

我们可以用VB查询关系数据库、XML和对象集合,根本不用学习任何领域专用语言,VB让我们可以访问任何东西!这样一来,我们就很很容易进行跨领域操作。(我会在之后的博客文章中提到这些)

XML作为第一类数据类型的同时,Visual Basic变成了完全的XML转换语言。对我来说,从数据库到XML做项目太容易了

        Dim query = From prod In db.Products _

            Where prod.Discontinued = True _

            Group By prod.CategoryID _

            Into prodGroup = Group, NumInStock = Sum(prod.UnitsInStock) _

            Join cat In db.Categories On cat.CategoryID Equals CategoryID _

            Select <Products>

                       <Category CategoryID=<%= CategoryID %> CategoryName=<%= cat.CategoryName %>>

                           <%= From prod In prodGroup _

                               Select <Product Price=<%= prod.UnitPrice %>><%= prod.ProductName %></Product> %>

                       </Category>

                   </Products>

如果你对LINQ(Language Integrated Query)不感兴趣,没关系,Visual Basic 2008还有其他的优点:强大的智能提示体验。我们的一个MVP说他写代码是只需要输入两个字母,按一下Tab键,两个字母,一下Tab …… 仿佛代码是自己写出来的!

诚然,我们对于这个发布十分激动,并希望它能为你带来更高的生产力!如果你想进一步研究它、了解更多功能,请参考Learning PagesHow-Do-I videos.

posted on 2008-01-18 16:44:00 by VBCTI  评论(17) 阅读(13866)

从SQL 到 LINQ, Part 4: 函数 (Bill Horst)

[原文作者]: Bill Horst

[原文链接]: Converting SQL to LINQ, Part 4: Functions (Bill Horst)

 

在看这篇文章之前,我假定你已经读过了:

SQLLINQPart 1:基础

SQLLINQPart 2FROMSELECT

SQLLINQPart 3DISTINCT, WHERE, ORDER BY 操作符

 

这篇文章讨论的是标量函数(scalar functions)和聚合函数(aggregate functions)。

 

函数

SQLSELECT子句经常会涉及到函数,包含标量函数和聚合函数。一个聚合函数针对的是select出来的一组记录,而标量函数针对的则是其中的个体。我们可以利用VB LINQ表达式实现这两种操作-但是,方法有所不同。

 

标量函数(Scalar Functions

标量函数不论参数如何操作的都是单个记录。他们可以在SQL查询的不同位置出现,比如SELCET子句。虽然标量函数会根据系统的不同而有所不同,但是我们总可以使用类似的VB方法在LINQ语句中进行模拟。如果在LINQSelect子句中使用标量函数,你可能也需要指定一个别名(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

 

 

在上面的例子中,LeftNowVB已有的方法(在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)。下面的例子展示了在SQLSELECT语句中如何使用集合函数,以及其在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)

用VB语言,在Web开发中使用LINQ

[原文作者]Paul Yuknewicz
[
原文链接]LINQ for the Web Using VB (By Paul Yuknewicz)

节日快乐!已经很长时间没有写点什么了,所以我觉得可以通过回答一些你们提交的好问题来进入新的一年

就在这个星期有人给我回复道:
"我在查找有关在web窗体中学习使用LINQ的信息时非常不顺利, 我希望组里的某个人可以给我一个方向. "

如你所言! 我们在学习中心对用VB描述的LINQ 和数据窗体给与了很大关注,  但有关LINQ与基于Web的数据窗体的内容却很少

如今的网络有很多伟大的创新,能够很容易利用LINQ的查询能力,并使之与Web用户界面的丰富新和灵活性相结合.的确很容易.

在开始之前你需要弄明白几个概念:

  • LinqDataSource 控件 -- 允许你在基于Web的数据绑定中使用LINQ查询作为数据源.
  • LinqDataSource.Selecting 事件 -- 允许你自定义LINQ定义查询(包括匿名查询) 为数据源只要从VB编辑器的下拉列表中选中LinqDataSource并选择Selecting事件,  然后在事件处理代码中设定e.Result = <你的LINQ查询> 即可.
  • OR设计器和Linq SQL -- 如果你正用LINQ查询直接连接到SQL数据库 (而不是对象集合, xml, 等等) , 这是一种创建查询的简单方法, 我们称它为DataContext 对象.  “OR”是对象-关系映射的缩写, 例如, 从关系数据库数据到.NET对象的映射
  • ASP.NET 数据绑定表达式 -- 使你能够计算由数据源字段,  或简单控件的属性,  或控件列表而来的ASP形式的<%# Eval("YOURFIELD") %>表达式

LINQSQL创建一个简单的Web窗体

    第一篇文章用一个最简单的Web窗体, 来逐一解释这些概念. 然后我将根据你们的回复在以后的文章中添加更多主题并扩展这个示例.

    下面是一个最初我们需要的Web窗体输出示例 -- 一个非常简单的人力资源程序的员工列表单 -- 我得承认它缺少修饰, 并需要一些用户界面上的加工:

    EmployeeID: 2
    Andrew Fuller
    Andrew received his BTS commercial in 1974 and a Ph.D. in international marketing from the University of Dallas in 1981. He is fluent in French and Italian and reads German. He joined the company as a sales representative, was promoted to sales manager in January 1992 and to vice president of sales in March 1993. Andrew is a member of the Sales Management Roundtable, the Seattle Chamber of Commerce, and the Pacific Rim Importers Association.

    EmployeeID: 1
    Nancy Davolio
    Education includes a BA in psychology from Colorado State University in 1970. She also completed "The Art of the Cold Call." Nancy is a member of Toastmasters International.

    如果你对Visual Studio非常熟悉, 我估计你只要1015分钟就能在你自己的机器上实现

准备

-     确保已经安装Visual Studio 2008 Visual Web Developer 2008 Express. Express 版本可以从这里下载.
-     
确保安装了 SQL Server 2005 Express 并已启动它通常在安装VS VS Express的同时默认被安装. 你也可以从这里下载安装
-   
如果在你的机器上没有Northwind.mdf, 可以从这篇文章的附件中下载.

为网站添加数据

    首先我们要把数据库添加到我们的工程中, 并创建必要的类以使用LINQ中的数据库 (LinqSQL).注意, 你可以选择跳过此步骤并创建你自己的LINQ查询到其他数据库上. 

  1. 通过File -> New Web Site ... -> ASP.NET Web Site创建一个新的网站到本地目录
  2. Northwind数据库添加到网站的App_Data文件夹
    1. 从本文附件中下载 Northwind.mdf 文件并保存到本地硬盘上
    2. 把这个文件拖放到解决方案管理器的App_Data文件夹中
       
  3. 通过OR设计器为Northwind创建LINQ SQL的类. Linq SQL 类会被保存在一个.dbml 文件中并可以在可视的OR设计器中打开
    1. 在解决方案资源管理器中右键单击网站结点, 选择快捷菜单的Add New Item -> Linq To SQL Classes
    2. "DataClasses.dbml" 重命名为"NorthwindDataClasses.dbml".  (这样做很重要, 以便在代码和VS向导中找到这些类).
    3. 当下图中的对话框出现时, 点击 Yes添加这个文件到App_Code 文件夹中这样做很重要, 因为网站需要动态地编译设计器生成的代码.. 
    4. 双击 NorthwindDataClasses.dbml 以便在OR设计器中打开它.
  4. 添加 Employees表的对象到你的 LinqSQL 类中
    1. 打开服务器管理器 (Express里是数据库管理器)
    2. 展开Northwnd.MDF -> Tables -> Employees
    3. 从服务器管理器中拖放Employees 表结点到NorthwindDataClasses.dbml 设计区域中(注意: 你可以继续添加更多的表, 或者存储过程, 或在设计器中自定义它们的名称/属性).
    4. 点击Save All按钮或菜单保存所有文件 

    
排列窗体界面和数据源控件

我们已经把数据库添加到网站上并创建了必要的LINQSQL, 现在应该添加一些用户界面元素并连接数据到界面上了. 我不会做任何太漂亮的东西 -- 只是重复地绑定一个DataList (你可以把它替换成GridView, FormView 或其他你喜欢的控件) 中的文本框

  1. 双击 Default.aspx , 在设计器中打开这个页面
  2. 从工具箱的Data选项卡中拖放一个DataListDefault.aspx 的设计区域中(或者拖放到”Source”视图的当前DIV标记区域内)
  3. 从工具箱的Data选项卡中拖放一个LinqDataSource 控件到 Default.aspx 的设计区域中(或者拖放到”Source”视图的DataList正下方)
连接 LinqDataSource 到底层数据(LINQ SQL - DataContext)

我们需要把LinqDataSource 连接到底层的LINQ数据上. 在这种情况下数据由任何一个基于NorthwindDataClasses 对象 (一个LINQSQL 文件) DataContext 对象或查询提供然后DataList可以直接把LinqDataSource 作为数据源, 并使用经典的Eval(“”) 语句通过绑定的字段显示数据如果你使用Smart Tags (智能标记), 设计器会为你生成一系列的默认值. 那我们就试试默认情况, 然后在此基础上做些调整

  1. 在设计器中选中 LinqDataSource 控件展开它的智能标签并点击Configure Data Source...
  2. 此时一个向导对话框会弹出, 并默认把NorthwindDataClasses 作为源.  (任何其他你添加的可供查询的源也会在这里显示).  点击Next. 
  3. 你可以选择任意列或字段. 本例中我选择*. 你甚至可以设置一个Where子句 -- 不过我认为在代码中作参数化的查询或其他类型的查询操作会更容易一些我过会儿会作个演示...  点击 Finish
  4. 你可以选择性地从LinqDataSource 的智能标签里启用Delete, Insert, Update.  提示: 如果你要建一个可读/写的web窗体, 这会非常有用

             

下面是在”Source”视图中可以看到的LinqDataSource 的标记. 注意ContextTypeName="NorthwindDataClassesDataContext" -- 这个值是我们在设计器中创建的类型名称 (代码生成器在末尾添加了一个"DataContext" -- 这名字真长!).  TableName 设置为我们想要显示的表或属性 -- 本例中设为Employees.  你可以用这种方法绑定任何现有的DataContext 类型和类属性

<asp:LinqDataSource ID="LinqDataSource1" runat="server" ContextTypeName="NorthwindDataClassesDataContext"
    TableName="Employees">
</asp:LinqDataSource>
绑定界面控件到 LinqDataSource

现在让我们把 DataList连接到 LinqDataSource.  有一个好消息是DataList只关心LINQ查询通过LinqDataSource返回的字段名称 -- 当你不断改进动态 LINQ查询的字段和行结果时会给你方便

  1. 在设计器中选中DataList. 展开智能标签并选择Data Source = LinqDataSource1
  2. 自定义一下DataListItemTemplate
  3. 运行!  (F5 或在快捷菜单中点击 View in Browser)

默认情况下向导会创建一系列绑定的文本标签. 你可以利用设计器在编辑模式下选取你想要的.提示: 这是我通常在”Source”视图中拖放html标记的地方. 在本例中, 我只简单地显示full name,  notes, 还有一块显示员工相片的地方. 并把数据转化到一个有两列的表格中

如果你检查一下DataList的标记, 你会发现ItemTemplate包含一些绑定的文本标签.  从查询中绑定数据是一个非常简单的过程,你只需要在服务器控件字段中, 用经典的ASP样式和VB eval数据绑定语句, 输入<%# Eval("YOURFIELDNAME") %>. 这为显示你想要的数据及格式化它们提供了很大的灵活性. 下面是我自定义的

<div>
    <asp:DataList ID="DataList1" runat="server" DataKeyField="EmployeeID" DataSourceID="LinqDataSource1">
        <HeaderTemplate>
            <table>
        </HeaderTemplate>
        <ItemTemplate>
            <tr>
                <td>
                    <img src="PLACEHOLDER.jpg" class="" style="border: 4px solid white" 
                         
alt='Photo Number XXX' />
                    <br /><br />
                </td>
                <td>
                    EmployeeID:
                    <asp:Label ID="EmployeeIDLabel" runat="server" Text='<%# Eval("EmployeeID") %>' />
                    <br />
                    <asp:Label ID="LastNameLabel" runat="server" 
                          
Text='<%# Eval("FirstName") & " " & Eval("LastName") %>' />
                    <br />
                    <asp:Label ID="NotesLabel" runat="server" Text='<%# Eval("Notes") %>' />
                </td>
            </tr>
        </ItemTemplate>
        <FooterTemplate>
            </table>
        </FooterTemplate>
    </asp:DataList>
</div>

 

使用自定义LINQ查询

上面的步骤提供了一个零代码实现绑定Web窗体到LINQ数据的方法. 但是, 你可能会问你自己, LINQVB去哪了?  确实是这样,LinqDataSource 隐藏了所有的查询代码并限制了你在设计器中可以做到的事情. 这对一些简单的例子来说足够了, LINQ真正强大的地方是可以使用任何窗体查询和VB逻辑. 好消息是LinqDataSource 支持使用你自己的LINQ查询处理LinqDataSource.Selecting事件.   这是你明确告诉控件应该用哪个查询的地方. 这很简单, 看下面:

  1. 右键单击Default.aspx 并选择View Code ...以显示文件的后台代码 (Default.aspx.vb). 
  2. 在代码编辑器左手边上方的下拉列表中选择LinqDataSource1 对象.
  3. 在代码编辑器右手边上方的下拉列表中选择Selecting 事件代码编辑器会自动定位到事件处理函数
  4. 在事件处理中编写你自定义的LINQ查询, 并确认在事件处理结束之前设置了e.Result = <your LINQ query variable>

在本例中我将查询Northwind数据库中的员工表 (Employees), 定义一个名为FullName (=First + Last)的自定义表达式 (Custom Expression) , 取以AN开头的全名(FullName), 最后按姓氏排序注意我为每个属性都创建了别名, 所以现在query是一个匿名类型 --  并且NorthwindDataContext 被默认地设置为所有列(*).  提示: 如果当你试着这样做时遇到运行时错误, 确认一下所有Web窗体需要的字段都存在. -- 例如: 如果窗体需要 "EmployeeID", 确认一下你的查询中包括这个字段.

Protected Sub LinqDataSource1_Selecting(ByVal sender As Object, ByVal e _
                                        As System.Web.UI.WebControls.LinqDataSourceSelectEventArgs) _
                                        Handles LinqDataSource1.Selecting
 
    Dim northwind As New NorthwindDataClassesDataContext
 
    'custom anonymous LINQ query
    Dim query = From emp In northwind.Employees _
                Select emp.EmployeeID, emp.FirstName, emp.LastName, emp.Notes, _
                    FullName = emp.FirstName & " " & emp.LastName _
                Where FirstName.ToUpper.StartsWith("A") Or FirstName.ToUpper.StartsWith("N") _
                Order By FullName
 
    'sets LinqDataSource query equal to custom query.  
    'use data binding expressions to look up aliased fields above. 
    e.Result = query
End Sub

你可以再次运行这个程序, 看看自定义查询是否有效 -- 只返回两行-- Andrew Fuller Nancy Davolio. 我们也可以调整一下标记代码以使用我们新定义表达式列 -- “FullName” . 下面是更改后DataList标记的样子:

<asp:DataList ID="DataList1" runat="server" DataKeyField="EmployeeID" DataSourceID="LinqDataSource1">
    <HeaderTemplate>
        <table>
    </HeaderTemplate>
    <ItemTemplate>
        <tr>
            <td>
                <img src="PLACEHOLDER.jpg" class="" style="border: 4px solid white" alt='Photo Number XXX' />
                <br /><br />
            </td>
            <td>
                EmployeeID:
                <asp:Label ID="EmployeeIDLabel" runat="server" Text='<%# Eval("EmployeeID") %>' />
                <br />
                <asp:Label ID="LastNameLabel" runat="server" Text='<%# Eval("FullName") %>' />
                <br />
                <asp:Label ID="NotesLabel" runat="server" Text='<%# Eval("Notes") %>' />
            </td>
        </tr>
    </ItemTemplate>
    <FooterTemplate>
        </table>
    </FooterTemplate>
</asp:DataList>
总结和更多信息

要想了解全部, 一个简单的方法是把你所知道的有关Web 窗体的与你在VB中学到的Linq作比较. LinqDataSource 连接底层LinqSQL DataContext或任何通用的Linq查询, 到你Web窗体的其余部分你可以在LinqDataSource.Selecting事件处理函数中创建完全自定义的查询, 并通过e.Result把它传递给控件然后你可以在你的Linq查询中使用经典的Eval("MYFIELD") 数据绑定表达式获取任何你想要的字段或属性.

怎么样? 你还想知道些什么?

如果你现在想得到更多地信息, ScottGu 在网络上发布了awesome series of Linq to SQL posts, 还添加了VB示例代码. 另一个重要的学习门户是www.asp.net

好运,

Paul

----------------------------------

Paul Yuknewicz
Lead Program Manager
Microsoft Visual Studio
http://msdn.com/vbasic/

附件:VBWebLINQSample-Complete.zip

posted on 2008-01-10 14:07:00 by VBCTI  评论(4) 阅读(5212)

Interop Forms Toolkit结合MySettings和WCF Configuration的应用

[原文作者]Beth Massi

[原文链接]Using My.Settings and WCF Configuration with the Interop Forms Toolkit

       最近有客户问到如何将基于Interop Forms Toolkit开发的Interop User Control通过读取app.config项目文件调用WCF service。(如果你不熟悉Interop user controls 开发请见can read these posts  watch these videos。)由于Interop user controls被编译成DLL文件,而生成的设置文件也以它命名,并不紧随VB 6应用程序,所以在运行时Interop User Control无法读取该文件里的设置。

      解决这个问题有一个简单的窍门,只要把bin目录下的.dll.config文件重命名成 VB6 EXE的名称,然后替换掉VB6 EXE所在目录下的同名文件。这样,运行WCF service client才能够读取指定的设置。

      或者你可以利用Build Events自动地为你去做这件事。只要双击Solution ExplorerMy Project打开项目属性,选择Compile栏,点击”Build Events”按钮,然后点”Edit Post-build…”. 在弹出的窗口中输入并执行复制命令,如:

copy /Y "$(TargetDir)$(ProjectName).dll.config" "$(ProjectDir)..\..\VB6App\Project1.exe.config"

      现在每当你更新Interop user control项目下的app.config文件,生成的.config settings就会被重命名和拷贝到VB6 应用程序目录下。

      然后我们谈谈My.Settings的应用, My.Settings使.NET程序存取应用级和用户级设置更简单,他们也是存放在app.config里的。但是仅仅重命名是不起作用的,因为My.Settings用到一种叫Settings Provider的驱动程序。在Visual Studio2005中默认的驱动者运用configuration系统加载和保存设置,生成设置文件,但是与WCFsettings的读取方式不同。

除了要重命名config文件,我们还要修改section标题下的name值成VB6EXE的名称(见添加的粗体字部分):

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

    <configSections>

        <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >

            <section name="AMyInteropUserControlLibrary1.My.MySettings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />

          <!--

          Using userSettings in a VB6 application:

          Change the name here to the name of your VB6 .EXE -->

            <section name="Project1.My.MySettings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />

        </sectionGroup>

        <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >

            <section name="AMyInteropUserControlLibrary1.My.MySettings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />

          <!--

          Using applicationSettings in a VB6 application:

          Change the name here to the name of your VB6 .EXE -->

          <section name="Project1.My.MySettings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />

        </sectionGroup>

    </configSections>

如果你通过项目属性的Settings栏新增设置, section groups就不会消失。现在你可以在项目部署以后更改.exe.config文件让你的Interop user control能够动态的读取设置。我已经附上完成的例子,包含WCF service, 为你在Visual Studio2005下演示。请阅读Readme文件以保证正确安装。

SettingsAndInteropUserControl.zip

posted on 2008-01-08 14:00:00 by VBCTI  评论(0) 阅读(4316)

LINQ 菜谱, 菜单4: 查找给定程序集中所有复杂类型 (Kit George)

[原文作者]Kit George

[原文链接]LINQ Cookbook, Recipe 4: Find all complex types in a given assembly (Kit George)

 

准备材料:

-        Visual Studio 2008 (Beta2 或更高版本)

        一个需要分析的程序集 (在这个例子中, 我们使用了用来存储字符串的mscorlib.dll 程序集)

-         一个 复杂类型的字义.  在这个例子中, 复杂类型包含10以上public方法,而且至少有一个方法具有3个以上的参数.

 

类别: LINQ-To-Objects, LINQ and types, LINQ and WinForms

 

制作方法:

-         打开 Visual Studio 2008,  点击菜单文件/新建项目”. 找到并双击 ”Windows 窗体应用程序  图标.

-        拖放一个 Listbox 到窗体上,调整Listbox的高度. 再拖放一个按钮到窗体上

       双击这个按钮, 并将以下代码添加到按钮的事件处理函数中:

 

Dim q = From type In System.Reflection.Assembly.GetAssembly( _

                  GetType(String)).GetTypes(), _

                  m In type.GetMethods() _

        Where type.IsPublic _

                  AndAlso type.GetMethods.Length > 10 _

                  AndAlso m.GetParameters.Length > 3 _

        Select type Distinct 

 

ListBox1.Items.AddRange(q.ToArray)

posted on 2008-01-08 11:00:00 by VBCTI  评论(3) 阅读(3907)

LINQ 菜谱, 菜单3: 在给定的范围内找到所有的素数(Jonathan Aneja)

[原文作者]Jonathan Aneja

[原文链接]LINQ Cookbook, Recipe 3: Find all the prime numbers in a given range (Jonathan Aneja)

 

准备材料:

-         Visual Studio 2008 (Beta2 或更高版本

 

类别: LINQ-To-Objects 

 

制作方法:

-         打开 Visual Studio 2008,  点击菜单 文件/新建项目”.  找到并双击 控制台应用程序  图标.

-         添加以下代码

     

Module Module1

 

    Sub Main()

        Dim primes = GetPrimesInRange(30, 50)

 

        For Each n In primes

            Console.WriteLine(n)

        Next

        Console.ReadLine()

    End Sub

 

    Function GetPrimesInRange(ByVal low, ByVal high) As IEnumerable(Of Integer)

        Dim range = Enumerable.Range(1, high)

        Return From num In range _

               From num2 In range _

               Where num Mod num2 = 0 _

               Group By num Into Count() _

               Where Count = 2 And num > low _

               Select num

    End Function

 

End Module

 

-         这里用到的grouping (分组), 只是为了选择那些有且仅有两个因子的数字. (例如: 它们是素数)

posted on 2008-01-07 10:29:00 by VBCTI  评论(1) 阅读(3871)

从SQL到LINQ, Part 3: DISTINCT, WHERE, ORDER BY and Operators (Bill Horst)

[原文作者]: Bill Horst

[原文链接]: Converting SQL to LINQ, Part 3: DISTINCT, WHERE, ORDER BY and Operators (Bill Horst)

 

在看这篇文章之前,我假定你已经读过了:

SQLLINQPart 1:基础

SQLLINQPart 2FROMSELECT

 

继续我们的话题,这次我将涉及的主题是DISTINCT, WHERE ORDER BY相关的内容。

 

DISTINCT

 

SQLSLECT语句可以指定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”

 

 

操作符

 

SQLWHERE子句可以包含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

 

SQLORDER BY子句可以使用ASCDESC关键字来指定升序和降序。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代码。下一次,我会谈到函数-包含ScalarAggregate

 

-      Bill Horst, VB IDE Test

 

posted on 2008-01-03 17:21:00 by VBCTI  评论(4) 阅读(6571)

Powered by: Joycode.MVC引擎 0.5.2.0