一起谈.NET技术,LINQ to SQL快速上手 step by step

  前言

      最近接连遇到几个朋友问我同一个问题,就是关于.NET平台上ORM框架的选择。我想在这个讲求效率的时代,谁也不想手写SQL或存储过程去访问数据库了。大家都知道,在Java平台上,ORM这一块基本是Hibernate的天下。当然,相对轻量级的iBatis也有不错的表现。
      不过谈到.NET平台,ORM框架似乎相对混乱了点。很多朋友问我的时候,往往会这样问:NHibernate、NBear和Castle该选择哪个?而当我反问:为什么不适用微软自带的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提供了丰富的功能,完全可以满足日常数据访问的需求。使用方法也非常简单、灵活。

      有这么好的理由,我真想不通为什么那么多人不愿去选择它。我想来想去,也许有两个重要原因,一是把LINQ和Linq to Sql混为一谈了,二是受前段时间“LINQ已死”的误导,觉得微软已经抛弃Linq to Sql了。关于这两点,我就不细说了,简略澄清一下:
      首先,LINQ是从.NET Framework3.0开始,.NET平台上引入的一种新式语言特性,狭义一点,你可以讲它理解成一种新式语法,主要是针对迭代数据操作的,所以,也许LINQ叫做“数据迭代引擎(Data Iterative Engine)”更合适,之所以不着样命名,我想微软可能不愿意让自己产品的简写为“DIE”吧。:-)而Linq to Sql是LINQ在数据库访问方面的一个应用框架,完全是两码事。
      其次,关于微软会不会放弃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,及两个数据表:Category和Bulletin,分别表示公告的分类和公告,建立方法不再赘述。至于两个表的具体字段请参看图1。

图1、数据表结构

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

  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节点,应该能看到Category和Bulletin两个表,选中两个表,将它们拖到DataClasses.dbml的设计区,就会看到如图4所示的样子。

图4、设计视图

      然后,按Ctrl+S保存,OK!ORM构建完了!
      没有骗你,所有需要的代码已经生成完成,现在可以使用它们操作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生成代码时会自动表示到类结构中。并且,这种关联是双向的。例如,Category与Bulletin的一对多关系,到了类结构中,反映成如下形式:在Category类中,有一个名为Bulletins的集合属性,内容是所有属于此Category的Bulletin对象的引用。而在Bulletin类中,也会有个Category1属性(由于Category这个名字被我们用了,所以,这个关联属性自动加了个“1”),其内容是此Bulletin所属Category对象的引用。

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

      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操作举例
      取得单个记录(ID为3的分类)

return dataContext.Categories.Single(c => c.ID == 3;

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

return dataContext.Categories;

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

return from b in dataContext.Bulletins
              where b.Category == 3
              orderby b.ID descending
              select b;

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

var bulletins = from b in dataContext.Bulletins
                       where b.Category == 3
                       orderby b.ID descending
                       select b;
return bulletins.Skip(pageSize * (pageNumber - 1)).Take(pageSize).ToList();

  总结

      好了,这篇文章就到这里了。希望能帮助大家快速上手Linq to Sql。关于Linq to Sql,还有许多丰富的功能和细节问题,篇幅原因不能详述,各位可以参考相关资料。

时间: 2024-08-01 14:32:58

一起谈.NET技术,LINQ to SQL快速上手 step by step的相关文章

LINQ to SQL快速上手 step by step

前言 最近接连遇到几个朋友问我同一个问题,就是关于.NET平台上ORM框架的选择.我想在这个讲求效率的时代,谁也不想手写SQL或存储过程去访问数据库了.大家都知道,在Java平台上,ORM这一块基本是Hibernate的天下.当然,相对轻量级的iBatis也有不错的表现. 不过谈到.NET平台,ORM框架似乎相对混乱了点.很多朋友问我的时候,往往会这样问:NHibernate.NBear和Castle该选择哪个?而当我反问:为什么不适用微软自带的Linq to Sql呢?对方经常会迷茫和不解.

一起谈.NET技术,基于SQL Server 2008 Service Broker构建企业级消息系统

1.引言 Microsoft 在SQL Server 2005引入了服务代理 (Service Broker 简称SSB) 为技术支持代理设计模式和面向消息的中间件 (MOM) 的原则.Service Broker在SQL Server 2008上得到完善, SQL Server Service Broker 为消息和队列应用程序提供 SQL Server 数据库引擎本机支持. 这使开发人员可以轻松地创建使用数据库引擎组件在完全不同的数据库之间进行通信的复杂应用程序.开发人员可以使用 Servi

Linq之Linq to Sql

目录 写在前面 系列文章 Linq to sql 总结 写在前面 上篇文章介绍了linq to xml的相关内容,linq to xml提供一种更便捷的创建xml树,及查询的途径.这篇文章将继续介绍linq to sql的内容.个人觉得linq to sql在实际开发中在中小型项目中用的比较多,在中小型项目用ef或者nhibernate这些orm确实有点重量级.Linq to Sql提供了丰富的功能,完全可以满足日常数据访问的需求.使用方法也非常简单.灵活. 系列文章 Linq之Lambda表达

一起谈.NET技术,【译】ASP.NET MVC并不仅仅只是Linq to SQL

很多ASP.NET的教程中的示例代码使用的数据访问方法是Linq to Sql或是Entity Framework.我在www.asp.net的论坛上看到很多关于讨论是否有其他替代的数据库访问方式,回答是:当然有.这篇文章就讲述了使用Ado.Net作为数据访问层来实现一个典型的增删查改程序. 由于是以练习作为目的,那我就不妨借用Spaanjaar's 的N层构架文章(Building Layered Web Applications with Microsoft ASP.NET 2.0.)的构架

一起谈.NET技术,Linq To SQL 批量更新方法汇总

方法一.官方例子 地球人都知道的,也是不少 Linq To SQL 反对者认为效率低下的一种方法. NorthwindDataContext db = new NorthwindDataContext(); var customers = db.Customers.Where(c => c.CustomerID.StartsWith("BL")); foreach (var customer in customers) { customer.Address = "Gua

一起谈.NET技术,维护LINQ to SQL多对多表间关系

在项目开发中,经常会碰到维护多对多(many to many)关系表间关系的操作,例如为人员配置角色.为人员配置部门.为产品配置类别等.如果没有经过程序设计而直接进行开发,将会过多地关注其细节问题,如:应删除那些数据.应添加哪些数据.应保留哪些数据等,导致开发效率降低. 名词解释 在本文开始之前,首先以用户-用户角色-角色表为例,声明三个概念: l  主表:如果为用户配置角色,那么用户就是主表:如果为角色配置用户,那么角色就是主表. l  从表:如果为用户配置角色,那么角色就是从表. l  关系

一起谈.NET技术,使用LINQ to SQL更新数据库(上):问题重重

在学习LINQ时,我几乎被一个困难所击倒,这就是你从标题中看到的更新数据库的操作.下面我就一步步带你走入这泥潭,请准备好砖头和口水,Follow me. 从最简单的情况入手 我们以Northwind数据库为例,当需要修改一个产品的ProductName时,可以在客户端直接写下这样的代码: // List 0NorthwindDataContext db = new NorthwindDataContext(); Product product = db.Products.Single(p =>

一起谈.NET技术,使用LINQ to SQL更新数据库(中):几种解决方案

在前一篇文章中,我提出了在使用LINQ to SQL进行更新操作时可能会遇到的几种问题.其实这并不是我一个人遇到的问题,当我在互联网上寻找答案时,我发现很多人都对这个话题发表过类似文章.但另我无法满足的是,他们尽管提出了问题,却没有进行详细的剖析,只给出了解决方案(如添加RowVersion列.去除关联等),但却没有说明为什么必须这么做.这也是我写上篇的初衷,希望通过对LINQ to SQL源代码的分析,来一步一步找出解决问题的办法.本文将对这些方法一一进行讨论. 方案一:重新赋值 在Terry

一起谈.NET技术,Linq to SQL T4 代码生成器 (二)访问设计器中的 Table 对象

在上一篇文章中,介绍了如何访问 DataContext 对象,下面接着来讲解一下如何访问设计器中的表对象,并生成生体类代码.从 Northwind 数据库中拖一个表到设计器中.拖出来后,记得保存 dbml 文件,否则是无法访问到这个表的. 在这里拖的是 Catories 表,如下图所示: 我们可以通过访问 DataContext.Tables 来访拖放到设计器中的表.代码如下: <# foreach(ITable table in DataContext.Tables){ }#> 现在再来看看