ScottGu博客之翻译-第8部分--使用自定义的SQL语句

感谢Dudu为我们带来运行速度更快的服务器!庆祝新服务器已上线!

在上几周中我写了一个概述了LINQ to SQL的帖子系列。LINQ to SQL是集成在.NET Framework3.5中的O/RM(对象关系映射)的实现,它让你非常容易地用.NET类来生成关系型数据库的模型。然后你可以用LINQ 表达式对它来进行查询,更新,插入删除。 下边是我的该系列的前七篇的帖子的链接:

在前两篇帖子中 (Part 6 and Part 7)我描述了如何用LINQ to SQL数据模型通过数据库的存储过程和用户自定义的函数来查询和检索数据。在今天的博客中我将讨论一下如何选择使用存储过程来更新、插入、删除数据。

自从我写了那些帖子之后,许多人问我的问题之一就是“如果我想完全控制linq to sql的sql表达式,并且我又不想用存储过程--我该怎么做?”今天的博客将会讲述这个问题--并且讨论一下如何使用自定义的sql表达式来控制你的linq to sql 数据模型类,对其插入、更新和删除。

和LINQ to SQL一起使用LINQ 查询表达式

为了完成今天帖子要讲述的内容,让我们假设已经用VS2008中的LINQ to SQL ORM设计器为Northwind数据库定义一个如下的数据模型类:(在本系列的第2部分Part 2 中讲述了如何用设计器定义此数据模型类):

ScottGu博客之翻译-第8部分--使用自定义的SQL语句

在本系列的第3部分(Part 3),我讲述了如何用在VB和C#中支持的新的LINQ语言来对上面的数据模型类进行查询,并且返回一个代表了数据库中的行/列关系的对象。

例如,我们可以向我们的数据模型的DataContext类中添加一个"GetProductsByCategory"的帮助方法 ,该方法用LINQ查询从数据库中进行查询并返回一个Product对象集合:

VB:

ScottGu博客之翻译-第8部分--使用自定义的SQL语句

C#:

ScottGu博客之翻译-第8部分--使用自定义的SQL语句

一旦我们定义了LINQ帮助方法,我们可以写如下的代码,用LINQ的帮助方法来检索产品并且对结果进行遍历:

VB:

ScottGu博客之翻译-第8部分--使用自定义的SQL语句

当"GetProductsByCategory"方法被调用时, LINQ to SQL ORM将会运行动态的SQL来检索产品数据。你可以在LINQ to SQL Debug Visualizer中查看这个LINQ表达式最终是如何生成的。

Using Custom SQL Queries with LINQ to SQL

和LINQ to SQL一起使用自定义的SQL查询

在上面的例子中,我们没有写任何的SQL代码来查询数据库和检索出强类型的产品对象。取代之的是,linq to sql orm会自动的将linq表达式翻译为sql语句,并且使用生成的sql语句对数据库进行操作。

可是,若是我们想完全控制对我们的数据库进行操作的sql语句,并且不想让linq to sql为我们自动生成的话,该怎么做呢?实现这个目的的方法之一是使用在本系列的第 六(Part 6)和第七( Part 7)部分讲解的存储过程。另外一个方法是使用在DataContext基类中的"ExecuteQuery"帮助方法,使用我们提供的自定义的sql表达式。

使用ExecuteQuery方法

ExecuteQuery方法将sql查询表达式作为参数,和一系列的我们可以选择使用参数列表。使用这一功能我们可以对数据库执行原始的sql语句(包括自定义的多表之间的连接)。

使ExecuteQuery方法真正有用的是它允许你声明以何种方式将sql表达式返回的值进行格式化。你可以通过如下两种方式来实现:或者向方法中传递一个类型对象作为参数,或者使用一个本方法的generic-based的版本。

例如,我们可以修改原来生成的GetProductsByCategory()的帮助方法-使用LINQ表达式--来替代ExecuteQuery方法来执行我们自己的原始的SQL表达式对数据库进行操作并返回"Product"对象:

VB:

ScottGu博客之翻译-第8部分--使用自定义的SQL语句

C#:

ScottGu博客之翻译-第8部分--使用自定义的SQL语句

然后我们可以调用GetProductByCategory()帮助方法,代码可以和前面的代码完全相同:

ScottGu博客之翻译-第8部分--使用自定义的SQL语句

但是和前面的不同的是,对数据库进行操作的是我们自定义的SQL表达式--而不是linq表达式生成的动态sql语句。

为更新自定义SQL表达式和对象跟踪

默认情况下,当你用LINQ to SQL从数据模型对象中检索数据时,它会跟踪所有的变化并且当你对对象进行更新时更新这些变化。如果你调用DataContext中的"SbumitChanges()"方法,它将会启动一个事务,并且将所有的变更更新至数据库中。我本系列的第四部分Part 4中对这一点进行的较深刻地讲解。

ExecuteQuery()的其中一个比较酷的我是,它完全参与跟踪和更新模型中。比如,我们可以写如下的代码查询属于某一类别的产品并且将它们的价格打折10%:

ScottGu博客之翻译-第8部分--使用自定义的SQL语句

因为我们将ExecuteQuery()方法调用的GetProductByCategory()方法的结果集转换为"Product"的类型,LINQ to SQL知道跟踪返回的Product对象。当我们调用Context对象中的"SubmitChanges()"方法时,它们将会被保存至数据库中。

自定义类中的自定义SQL表达式

ExecuteQuery()方法允许你指定任何类来作为SQL查询的返回值类型。该类不是必须用LINQ to SQL ORM设计器生成的或者实现了某些自定义的接口-你可以将旧的类指定给它作为它的返回值类型。

例如,我可以定义一个新的ProductSummary类,该类含有Product的属性是Product类的属性的一个子集,包括如下这些属性(注意新的C#的自动属性Automatic Properties特性):

ScottGu博客之翻译-第8部分--使用自定义的SQL语句

然后我们可以在NorthwindDataContext中生成一个将该类作为返回值类型的GetProductSummariesByCatetory()帮助方法。注意下面的SQL声明是如何只请求Product中的我们需要的属性的值的--ExecuteQuery()方法自动处理它返回的ProductSummary对象:

ScottGu博客之翻译-第8部分--使用自定义的SQL语句

然后我们可以执行这个帮助方法并且用下面的代码来对结果集进行遍历:

ScottGu博客之翻译-第8部分--使用自定义的SQL语句

用于插入、更新、删除的自定义的SQL表达式

除了对查询使用自定义的SQL表达式,我们也可以执行它们来进行插入、更新、删除的逻辑。

我们可以通过如下方式实现这个目的:在DataContext的一个局部类中生成一个适当的插入、更新、删除的局部方法。然后使用ExecuteCommand方法来写我们需要执行的SQL语句。例如,为了为产品类覆盖删除的方法,我们可以定义如下的一个DeleteProduct局部方法:

ScottGu博客之翻译-第8部分--使用自定义的SQL语句

然后如果我们写如下的代码从数据库中移除一个特定的产品实例,LINQ to SQL将会调用DeleteProduct方法--该方法将会引起我们自定义的SQL语句替代自动生成的SQL语句:

ScottGu博客之翻译-第8部分--使用自定义的SQL语句

总结

LINQ to SQL ORM自动生成并运行动态的SQL语句来对数据库进行查询、更新、插入和删除。

在一些高级的场景中,或者在你想完全控制执行的SQL语句的情况下,你依然能够自定义ORM来或者使用存储过程,或者使用你自己定义的SQL表达式来替代原来它自动生成的SQL语句。这在创建和扩展你的数据层的时候给你提供了非常大的灵活性。

在接下来的本系列的帖子中,我将描述一些余下的LINQ to SQL概念,包括:单表继承,延迟/提前加载,优化并发冲突,处理多个场景。

希望这些对你有所帮助,

Scott