手把手教你用好LINQ to SQL

最近接连遇到几个朋友问我同一个问题,就是关于.NET平台上ORM框架的选择。我想在这个讲求 效率的时代,谁也不想手写SQL或存储过程去访问数据库了。大家都知道,在Java平台上,ORM 这一块基本是Hibernate的天下。当然,相对轻量级的iBatis也有不错的表现。

不过谈到.NET平台,ORM框架似乎相对混乱了点。很多朋友问我的时候,往往会这样问: NHibernateNBearCastle该选择哪个?而当我反问:为什么不适用微软自带的Linq to SQL 呢?对方经常会迷茫和不解。

我觉得这是个很奇怪的现象。依照我个人的实践,我认为当需要快速构建一个中小型项目时 Linq to SQL是一个很好的选择。你至少有以下理由可以选择它:

i. 它是微软自己的产品,和.NET平台有着天生的适应性。如果你使用.NET Framework3.5 VS2008开发环境,它本身就集成在里面了,同时VS2008对于Linq to SQL给予了诸多方便的支持 。使用它,你不仅在开发和部署时不用考虑第三方库,更可以尽情享受VS2008带来的种种方便 

ii. 上手十分容易,使用十分轻松,通常,你不需要编写一行代码,也不用写任何XML配置 ,完全通过可视化拖拽就能完成ORM层的构建。

iii. 功能丰富,使用便捷。当轻松构建好ORM层后,你就可以更轻松的操纵数据库了。Linq to SQL提供了丰富的功能,完全可以满足日常数据访问的需求。使用方法也非常简单、灵活。

有这么好的理由,我真想不通为什么那么多人不愿去选择它。我想来想去,也许有两个重要 原因,一是把LINQLinq to SQL混为一谈了,二是受前段时间"LINQ已死"的误导,觉得微软 已经抛弃Linq to SQL了。关于这两点,我就不细说了,简略澄清一下:

首先,LINQ是从.NET Framework3.0开始,.NET平台上引入的一种新式语言特性,狭义一点 ,你可以讲它理解成一种新式语法,主要是针对迭代数据操作的,所以,也许LINQ叫做"数据 迭代引擎(Data Iterative Engine"更合适,之所以不着样命名,我想微软可能不愿意让自 己产品的简写为"DIE"吧。:-)Linq to SQLLINQ在数据库访问方面的一个应用框架,完全 是两码事。

其次,关于微软会不会放弃Linq to SQL,客观说,可能会,因为微软下一步主推的ORM解决 方案是Entity Framework。不过这并不妨碍你学习使用Linq to SQL,原因如下:第一,考虑到 兼容性问题,微软绝对不会把Linq to SQL.NET Framework中拿掉的,所以你不用怕现在用 Linq to SQL写的程序以后不能运行了。第二,即使微软不更新Linq to SQL了,但它现在的功 能,已经足够满足我们日常需要了,相比重量级的Entity Framework,如果你只是做一个中小 型项目,并且很注重开发效率和学习曲线,为什么不选择可爱的Linq to SQL呢?

好的,上面废话说了不少,下面正式开始吧。本文不是一篇关于Linq to SQL的大百科,写 本文的目的,是引导大家快速上手Linq to SQL,所以不可能面面俱到去讲解Linq to SQL。不 过根据80-20定律,学会了本文的内容,基本就可以应付80%的工作了。另外,延续我一贯的风 格,本文将通过案例的方式帮大家上手Linq to SQL。案例是一个"公告发布程序"。下面我们 开始!

Step1:建立数据库

在使用Linq to SQL前,我们要将相应的数据库建好。在这个Demo中,使用的数据 库是SQL Server Express 2005

我们首先建立一个叫的数据库MyBulletin,及两个数据表:CategoryBulletin,分别表示 公告的分类和公告,建立方法不再赘述。至于两个表的具体字段请参看图1

1、数据表结构

其中CategoryBulletin存在一个一对多的关联,表示一个分类下可以有多条公告。

Step2:建立Linq to SQL Classes文件

数据建好后,我们需要建立Linq to SQL Classes文件。这种文件是Linq to SQL框架的主要 文件,后面自动生成的实体类和ORM代码都存在于这个文件中。

我们打开VS2008,新建一个C# Class Labrary工程,名称为LinqToSqlDemo.Orm,建好后在 工程上单击右键,选择"Add"->"New Item",在文件类型中选择"Linq to SQL Classes ",文件名命名为"DataClasses.dbml",如图2所示。

2、新建Linq to SQL Classes文件

Step3:根据数据库表自动生成代码

当建好Linq to SQL Classes后,VS主界面中自动打开了这个文件。可以看到,这 个文件实际是一个设计文件,目前还不包含任何代码和元素。下一步就是利用我们刚才的数据 库自动生成ORM代码了。

打开Server Explorer面板。一般它位于VS的左上角,如果没有,请到View菜单中去打开。 然后在Date Connections上右键单击,选择"Add Connection",从这里添加对数据库 MyBulletin的连接。

3、添加数据库连接

如图3所示,在Server name中填入SQL Server数据库服务的名字,如果使用的是SQL Server Express 2005,服务名一般是"计算机名\SQLEXPRESS"的格式,然后在"Select or enter a database name"中选择MyBulletin,单击"OK",就连上我们所需的数据库了。

这时,展开这个连接下的Tables节点,应该能看到CategoryBulletin两个表,选中两个表 ,将它们拖到DataClasses.dbml的设计区,就会看到如图4所示的样子。

4、设计视图

然后,按Ctrl+S保存,OKORM构建完了!

没有骗你,所有需要的代码已经生成完成,现在可以使用它们操作MyBulletin数据库了。不 要怀疑,Linq to SQL使用起来就是这么轻松加愉快,不需要写一行代码,也不需要写一个XML 字符,ORM就构建完了!

我知道你没看到生成的东西可能不太放心,那么你可以在Solution Explorer里展开 DataClasses.dbml节点,看到里面的DataClasses.designer.cs文件没,打开它,里面就是刚才 自动生成的代码,我们的数据访问操作就靠这些代码了。另外顺表提一下,数据库的连接字符 串放在工程根目录下的app.config文件里,这也是自动生成的,打开它,就可以看到连接字符 串。以后如果要修改连接字符串,就修改这里

好了,ORM构建好了,下面我们看看怎么用。

Step4:使用Linq to SQL访问数据库

我们首先新建一个工程。为了简单起见,我们就直接建立一个C# Console Application测试 我们的ORM吧。将这个工程命名为LinqToSqlDemo.Test。当然,建好工程后,不要忘了添加对工 LinqToSqlDemo.Orm的引用,还要添加对"System.Data.Linq"命名空间的引用。

然后,我们打开Program.cs文件,将其中的内容替换为如下测试代码。

 
using System;

using System.Collections.Generic;

using System.Data.Linq;

using System.Linq;

using System.Text;

 

using LinqToSqlDemo.Orm;

 

namespace LinqToSqlDemo.Test

{

    class Program

    {

        private static DataClassesDataContext dataContext = new DataClassesDataContext();

 

        private static void Output()

        {

            //输出分类信息

            foreach (Category c in dataContext.Categories)

            {

                Console.WriteLine("分类" + c.ID + "" + c.Name);

            }

 

            //输出体育新闻下的公告信息

            Category categorySport = dataContext.Categories.Single(c => c.Name == "体育新闻");

            foreach (Bulletin b in categorySport.Bulletins)

            {

                Console.WriteLine("标题:" + b.Title);

                Console.WriteLine("内容:" + b.Content);

                Console.WriteLine("发布日期:" + b.Date);

                Console.WriteLine("所属分类:" + b.Category1.Name);

            }

        }

 

        private static void TestInsert()

        {

            //生成分类实体类

            Category category1 = new Category()

            {

                Name = "国际要闻"

            };

            Category category2 = new Category()

            {

                Name = "体育新闻"

            };

            Category category3 = new Category()

            {

                Name = "财经快报"

            };

 

            //生成公告实体类

            Bulletin bulletin1 = new Bulletin()

            {

                Content = "曼联晋级冠军杯四强",

                Date = DateTime.Now,

                Title = "曼联晋级冠军杯四强"

            };

            Bulletin bulletin2 = new Bulletin()

            {

                Content = "18:00直播亚冠首尔VS山东,敬请期待!!!",

                Date = DateTime.Now,

                Title = "18:00直播亚冠首尔VS山东"

            };

 

            //将公告加入相应分类

            category2.Bulletins.Add(bulletin1);

            category2.Bulletins.Add(bulletin2);

 

            //加入数据库

            dataContext.Categories.InsertOnSubmit(category1);

            dataContext.Categories.InsertOnSubmit(category2);

            dataContext.Categories.InsertOnSubmit(category3);

            dataContext.SubmitChanges();

        }

 

        private static void TestDelete()

        {

            dataContext.Categories.DeleteOnSubmit(dataContext.Categories.Single(c => c.Name == "国际要闻"));

            dataContext.SubmitChanges();

        }

 

        private static void TestUpdate()

        {

            Category categoryFinance = dataContext.Categories.Single(c => c.Name == "财经快报");

            categoryFinance.Name = "财经新闻";

            dataContext.SubmitChanges();

        }

 

        static void Main(string[] args)

        {

            Console.WriteLine("==============================Linq to SQL 测试==============================");

            Console.WriteLine();

 

            Console.WriteLine("==============================测试Insert==============================");

            Console.WriteLine();

            TestInsert();

            Output();

 

            Console.WriteLine("==============================测试Delete==============================");

            Console.WriteLine();

            TestDelete();

            Output();

 

            Console.WriteLine("==============================测试Update==============================");

            Console.WriteLine();

            TestUpdate();

            Output();

 

            Console.ReadLine();

        }

    }

}


一下子看不懂上述代码页没有关系,稍候我们会解释一下。现在,我们先来看运行结果:

5、测试程序运行结果

我们先来看看这段测试程序做了什么事。刚开始,数据库是空的,我们首先插入三个分类, 并在"体育新闻"下插入两条公告,这是对Insert的测试。接着,我们删除了"国际要闻" 类,这是对Delete的测试。然后,我们将"财经快报"改为"财经新闻",这是对Update测试 。另外,整个过程的输出当然是对Select的测试。这样,数据库基本的操作都测试过了。从输 出结果来看,我们的ORM组件运行很顺利,程序输出正确。

程序分析

经过简单的四步,我们就完成了通过Linq to SQL操作数据库的过程。下面我们对 测试代码进行一个简要的分析,帮助朋友们学会Linq to SQL操作数据库的基本方法。

取得数据库Gateway

要操作数据库,我们首先要获得一个DataContext对象,这个对象相当于一个数据 库的Gateway,所有的操作都是通过它进行的。这个对象的名字是"Linq to SQL Classes文件 +'DataContext'",这里,就是DataClassesDataContext了。它和普通对象一样,直接实 例化就行了。在Demo里我将它实例化为一个静态变量。

取得DataContext对象后,每个数据表就会映射到其一个集合属性,例如Category表映射到 dataContext.Categories,这是一个集合属性,每一个元素是一个实体类,代表此表中的一条 记录。实体类名和表名相同。实体类的字段自然就映射到对应表的字段。

还有一点需要注意,数据库中的一对多关系,在Linq to SQL生成代码时会自动表示到类结 构中。并且,这种关联是双向的。例如,CategoryBulletin的一对多关系,到了类结构中, 反映成如下形式:在Category类中,有一个名为Bulletins的集合属性,内容是所有属于此 CategoryBulletin对象的引用。而在Bulletin类中,也会有个Category1属性(由于Category 这个名字被我们用了,所以,这个关联属性自动加了个"1"),其内容是此Bulletin所属 Category对象的引用。

Insert操作

Insert用于向数据库添加记录。一般情况下,使用"DataContext.表映射集 .InsertOnSubmit(实体类)"的方式就可以完成Insert操作。不过这里要注意一点,由于Linq to SQL使用了"Unit of Work"模式,所以,对数据库的操作不会立即提交到数据库,而要调 DataContextSubmitChanges方法,所有改动才会被提交到数据库。

Delete操作

Delete操作用于从数据库中删除记录。表映射集合的DeleteOnSubmit方法可以实 现这个操作。这个方法需要一个参数,就是要删除的实体类,这里不能直接传个ID去删除,要 首先通过ID找到相应实体类,传给DeleteOnSubmit再删除。当然最后不要忘了SubmitChanges

Update操作

Update操作用于更新数据库中某已存在记录的信息。在Linq to SQL中,Update 作就是首先加载相应的实体类,修改其相应字段后,SubmitChanges就可以了。

Select操作

Select操作用于从数据库中返回指定的记录。在Linq to SQL中,查询结果都是以实体类或 实体类集合的方式返回的。其中实体类集合并不是List,如果想转为List,只需在返回结果上 调用ToList方法即可。

如果是查询单一记录,建议使用表映射集合的Single方法。至于查询参数,建议采用lambda 表达式。如果你对lambda表达式不熟,可以参考这里http://msdn.microsoft.com/zh- cn/library/bb397687.aspx

其它相关示例代码

常用Select操作举例

取得单个记录(ID3的分类)

RETURNDATACONTEXT.CATEGORIES.SINGLE(C=>C.ID==3;

取得全部记录(全部分类)

RETURNDATACONTEXT.CATEGORIES;

得部分记录(所属分类ID3的公告,按ID降序排列)

RETURNFROMB<indatacontext.bulletins

orderbyb.IDdescending

selectb;

</indatacontext.bulletins

取得部分记录并分页,最后转换为List(所属分类ID3的公告并分页,pageSize为每页多 少条记录,pageNo为第几页)

varbulletins=frombINDATACONTEXT.BULLETINS

orderbyb.IDdescending

selectb;

<returnbulletins.skip(pagesize*(pagenumber-1)).take(pagesize).tolist();< pre="" style="font-family: 'Segoe UI', monospace !important;"></returnbulletins.skip(pagesize*(pagenumber-1)).take(pagesize).tolist();<>


LINQ to SQL语句(1)之Where 2 Where操作 2 1.简单形式: 2 2.关系条件形式: 2 3.First()形式: 3 LINQ to SQL语句(2)之Select/Distinct 3 1.简单用法: 4 2.匿名类型 形式: 4 3.条件形式: 5 4.指定类 型形式: 6 5.筛选形式: 6 6.shaped形式(整形类型): 6 7.嵌套类型形式: 7 8.本地方法调用 形式(LocalMethodCall): 7 9.Distinct形式: 8 LINQ to SQL语句(3)之Count/Sum/Min/Max/Avg 9 1.简单形式: 9 2.带条件形 式: 9 1.简单形式: 10 2.映射形式: 10 3.元素 : 11 1.简单形式: 11 2.映射形式: 11 3.元素: 11 1.简单形式: 12 2.映射形式: 12 3.元素: 12 LINQ to SQL语句(4)之Join 13 Join操作符 13 1.一对多关系(1 to Many): 13 2.多对多关系(Many to Many): 14 3.自联接关系: 15 1.双向联接(Two way join): 15 2.三向联接(There way join): 16 3.左外部联接(Left Outer Join): 17 4.投影的Let赋值(Projected let assignment): 17 5.组合键(Composite Key): 18 6.可为null/不可为null的键关系 (Nullable/Nonnullable Key Relationship): 19 LINQ to SQL语句(5)之Order By 19 Order By操作 19 1.简单形式 19 2.带条件形式 20 3.降序排序 20 4.ThenBy 20 5.ThenByDescending 22 6. 带GroupBy形式 22 LINQ to SQL语句(6)之Group By/Having 23 Group By/Having操作符 23 1.简单形式: 23 2.Select匿名类 : 24 3.最大 值 25 4.最小 值 26 5.平均 值 26 6.求和 26 7.计数 27 8.带条件计数 27 9.Where限制 28 10.多列(Multiple Columns) 28 11.表达式(Expression) 29 LINQ to SQL语句(7)之Exists/In/Any/All/Contains 29 Exists/In/Any/All/Contains操作符 29 Any 29 1.简单形式: 29 2.带条件形式: 30 All 30 Contains 31 1.包含一个对象: 31 2.包含多个值: 32 LINQ to SQL语句(8)之Concat/Union/Intersect/Except 32 Concat/Union/Intersect/Except操作 32 Concat(连接) 32 1.简单形式: 33 2.复 合形式: 33 Union(合并) 33 Intersect(相交) 34 Except(与非) 34 LINQ to SQL语句(9)之Top/Bottom和Paging和SqlMethods 35 Top/Bottom操作 35 Take 35 Skip 35 TakeWhile 36 SkipWhile 36 Paging(分页)操作 36 1.索引 36 2.按唯一键排序 36 SqlMethods操作 37 Like 37 已编译查 询操作(Compiled Query) 38 LINQ to SQL语句(10)之Insert 38 插入(Insert)1.简单形式 38 2.一对多 关系 39 3.多对多关系 39 4.使用动态CUD重写(Override using Dynamic CUD) 40 LINQ to SQL语句(11)之Update 41 更新(Update) 41 1.简单形式 41 2.多项更改 41 LINQ to SQL语句(12)之Delete和使用Attach 42 删除(Delete)1.简单形式 42 2.一对多关系 42 3.推理删除(Inferred Delete) 43 使用Attach更新(Update with Attach) 43 LINQ to SQL语句(13)之开放式并发控制和事务 46 Simultaneous Changes开放式并发控制 46 开放式并发(Optimistic Concurrency) 46 1.Implicit(隐式) 48 2.Explicit(显式) 48 LINQ to SQL语句(14)之Null语义和DateTime 49 Null语义 49 1.Null 49 2.Nullable<T>.HasValue 50 日期函数 50 1.DateTime.Year 51 2.DateTime.Month 51 3.DateTime.Day 51 LINQ to SQL语句(15)之String 51 字符串(String) 51 1.字符 串串联(String Concatenation) 52 2.String.Length 52 3.String.Contains(substring) 52 4.String.IndexOf(substring) 52 5.String.StartsWith (prefix) 53 6.String.EndsWith(suffix) 53 7.String.Substring(start) 53 8.String.Substring (start, length) 53 9.String.ToUpper() 54 10.String.ToLower() 54 11.String.Trim() 54 12.String.Insert(pos, str) 54 13.String.Remove(start) 55 14.String.Remove(start, length) 55 15.String.Replace(find, replace) 55 LINQ to SQL语句(16)之对象标识 56 对象标识 56 对象缓存 56 LINQ to SQL语句(17)之对象加载 57 对象加载延迟加载 57 预先加载:LoadWith 方法 58 LINQ to SQL语句(18)之运算符转换 59 1.AsEnumerable:将类型转换为泛型 IEnumerable 59 2.ToArray:将序列转换为数组 59 3.ToList:将序列转换为 泛型列表 59 4.ToDictionary:将序 列转化为字典 60 LINQ to SQL语句(19)之ADO.NET与LINQ to SQL 60 1.连接 61 2.事务 61 LINQ to SQL语句(20)之存储过程 63 1.标量返回 63 2.单一结 果集 64 3.多个可 能形状的单一结果集 65 4.多个结果集 70 5.带输出参数 79 LINQ to SQL语句(21)之用户定义函数 80 1.在Select中使用用户定义的标量函数 80 2.在Where从句中 使用用户定义的标量函数 81 3.使用用户定义的表值函数 83 4.以联接方式使用用户定义的表值函数 84 LINQ to SQL语句(22)之DataContext 85 创建和删除数据库 85 数据库验证 88 数据库更改 88 动态查询 89 日志 90 LINQ to SQL语句(23)之动态查询 90 1.Select 91 2.Where 92 LINQ to SQL语句(24)之视图 94 LINQ to SQL语句(25)之继承 96 1.一般形式 97 2.OfType形式 98 3.IS形式 98 4.AS形式 99 5.Cast形式 99 6.UseAsDefault形式 100 7.插入新的记录 101
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值