ADO.NET与ORM的比较(3):Linq to SQL实现CRUD

 说明:个人感觉在Java领域大型开发都离不了ORM的身影,所谓的SSH就是Spring+Struts+Hibernate,除了在学习基础知识的时候被告知可以使用JDBC操作数据库之外,大量的书籍中都是讲述使用Hibernate这个ORM工具来操作数据。在.NET中操作数据库的方式有多种,除了最直接的方式就是使用ADO.NET之外,还可以使用NHibernate这个Hibernate在.NET中的实现ORM,如果你对第三方的ORM持怀疑态度,你还可以使用来自微软的实现、根正苗红的Linq或者EntityFramework。
 大部分从早期就开始使用.NET开发的程序员可能对ADO.NET有种迷恋,使用ADO.NET可以充分将我们早期的SQL知识发挥得淋漓尽致,并且出于对性能的考虑,有些人对.NET中的ORM还保持一种观望态度,包括我自己也是这种态度。不过即使在实际开发中不用,并不代表我们不能去了解和比较这些技术,任何事物的出现和消亡总有其原因的,我们可以了解它们的优点和长处。所以本人抽出了几个周末的时间分别用ADO.NET、NHibernate、Linq和EntityFramework来实现对数据库单表数据的创建、读取、更新和删除操作,也就是所谓的CRUD(C:Create/R:Read/U:Update/D:Delete)。
 通过实现相同功能的比较,大家自己判断那种方式更适合自己。需要说明的是,如果在VS2008中使用EntityFramework就需要安装VS2008SP1。
 语言集成查询 (LINQ) 是 Visual Studio 2008 中的一组功能,可为 C# 和 Visual Basic 语言语法提供强大的查询功能。LINQ 引入了标准的、易于学习的查询和更新数据模式,可以对其技术进行扩展以支持几乎任何类型的数据存储。Visual Studio 2008 包含 LINQ 提供程序的程序集,这些程序集支持将 LINQ 与 .NET Framework 集合、SQL Server 数据库、ADO.NET 数据集和 XML 文档一起使用。
 在本篇讲述利用Linq实现对数据库的CRUD功能,也就是Linq to SQL,需要说明的是Linq to SQL只支持SQL Server数据库,Linq to SQL只是Linq的一部分功能。
 用Linq to SQL来操作数据库确实比使用NHibernate在操作上要方便得多,通过下面的操作读者也会体会得到,毕竟这个是微软官方的东东,微微支持的力度自然要大些。
 一、准备
 首先,向项目中添加Linq To SQL的类,如下图所示:
 linq
 在名称一栏中填写较友好的名字之后,然后项目中就会增加一个后缀为dbml的文件,双击这个文件就会进入设计视图,如下图所示:
 5
 在服务器资源管理中找到相应的数据库连接,依次点开之后就可以将数据库中的表拖到dbml设计器上。如果读者界面上没有服务器资源管理器可以使用CTRL+ALT+S组合键将其调出来。如果没有数据库连接,可以按照下面的步骤进行,在服务器资源管理器中的“数据连接”——“添加连接”,出现如下界面:
 
 
 在上面的界面中依次填写好数据库、用户名和密码及要连接的库名之后,点击确定,这样在服务器资源管理器中就增加了一个数据库连接,展开之后如下图所示:
 
 拖拽一个表到dbml上就会自动生成这个表的实体类,如下图所示:
 2
 也许有人会思考这个类的定义在哪里,可以告诉你的是这个类的定义在这个dbml文件对应的cs文件中(dbml文件名.designer.cs这种形式),如下图所示:
1 
 有些这些之后我们就可以动手编码实现对数据库进行CRUD操作了。
 二、编码
 由于在dbml文件中已经存在了DataContext和UserInfo表对应的UserInfo实体类,所以我们仅仅需要编写对数据库操作的类就可以了。编写的代码如下:

[c-sharp]  view plain copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Data.SqlClient;  
  6. using System.Data.Linq;  
  7. using System.Configuration;  
  8.   
  9. namespace LinqDemo  
  10. {  
  11.     /// <summary>  
  12.     /// 说明:这个类是为了演示.NET中的Linq to SQL的用法  
  13.     /// 作者:周公(周金桥)  
  14.     /// 日期:2010-03-01  
  15.     /// </summary>  
  16.     public class LinqCRUD  
  17.     {  
  18.         /// <summary>  
  19.         /// 统计用户总数  
  20.         /// </summary>  
  21.         /// <returns></returns>  
  22.         public int Count()  
  23.         {  
  24.             #region 方法一  
  25.             //使用SqlConnection来实例化DataContext对象  
  26.             SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["LinqDemo.Properties.Settings.AspNetStudyConnectionString"].ConnectionString);  
  27.             DataContext context = new DataContext(connection);  
  28.             IEnumerable<int> collection = context.ExecuteQuery<int>("select count(1) from UserInfo");  
  29.             int count = collection.ElementAt<int>(0);  
  30.             return count;  
  31.             #endregion  
  32.  
  33.             #region 方法二  
  34.             //UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();  
  35.             return context.UserInfo.Count<UserInfo>(item => item.Age > 23);//带条件统计  
  36.             //return context.UserInfo.Count<UserInfo>();  
  37.             #endregion  
  38.         }  
  39.         /// <summary>  
  40.         /// 创建用户  
  41.         /// </summary>  
  42.         /// <param name="info">用户实体</param>  
  43.         /// <returns></returns>  
  44.         public void Create(UserInfo info)  
  45.         {  
  46.             UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();  
  47.             context.UserInfo.InsertOnSubmit(info);  
  48.             context.SubmitChanges();  
  49.         }  
  50.         /// <summary>  
  51.         /// 读取用户信息  
  52.         /// </summary>  
  53.         /// <param name="userId">用户编号</param>  
  54.         /// <returns></returns>  
  55.         public UserInfo Read(int userId)  
  56.         {  
  57.             UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();  
  58.             context.Log = Console.Out;  
  59.             var query = from item in context.UserInfo  
  60.                         where item.UserID == userId  
  61.                         select item;  
  62.             return query.First<UserInfo>();  
  63.         }  
  64.         /// <summary>  
  65.         /// 更新用户信息  
  66.         /// </summary>  
  67.         /// <param name="info">用户实体</param>  
  68.         /// <returns></returns>  
  69.         public void Update(UserInfo info)  
  70.         {  
  71.             UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();  
  72.             UserInfo ui = context.UserInfo.First<UserInfo>(item => item.UserID == info.UserID);  
  73.             ui.Age = info.Age;  
  74.             ui.Email = info.Email;  
  75.             ui.Mobile = info.Mobile;  
  76.             ui.Phone = info.Phone;  
  77.             ui.RealName = info.RealName;  
  78.             ui.Sex = info.Sex;  
  79.             ui.UserName = info.UserName;  
  80.             context.SubmitChanges();  
  81.         }  
  82.         /// <summary>  
  83.         /// 删除用户  
  84.         /// </summary>  
  85.         /// <param name="userId">用户编号</param>  
  86.         /// <returns></returns>  
  87.         public void Delete(int userId)  
  88.         {  
  89.             #region 方法一  
  90.             //UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();  
  91.             //context.ExecuteCommand("delete from UserInfo where UserId=" + userId);  
  92.             #endregion  
  93.             #region 方法二  
  94.             UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();  
  95.             UserInfo ui = context.UserInfo.First<UserInfo>(item => item.UserID == userId);  
  96.             context.UserInfo.DeleteOnSubmit(ui);  
  97.             context.SubmitChanges();  
  98.             #endregion  
  99.         }  
  100.   
  101.         /// <summary>  
  102.         /// 删除用户  
  103.         /// </summary>  
  104.         /// <param name="userId">用户实体</param>  
  105.         /// <returns></returns>  
  106.         public void Delete(UserInfo info)  
  107.         {  
  108.             UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();  
  109.             var userList = from Users   
  110.                              in context.UserInfo  
  111.                              where Users.UserID == info.UserID   
  112.                              select Users;  
  113.             foreach (var user in userList)  
  114.             {  
  115.                 context.UserInfo.DeleteOnSubmit(user);  
  116.             }  
  117.             //context.UserInfo.DeleteOnSubmit(userList.First<UserInfo>());  
  118.             //注意下面的写法是错误的  
  119.            // context.UserInfo.DeleteOnSubmit(info);  
  120.             context.SubmitChanges();  
  121.         }  
  122.   
  123.         /// <summary>  
  124.         /// 获取用户表中编号最大的用户  
  125.         /// </summary>  
  126.         /// <returns></returns>  
  127.         public int GetMaxUserId()  
  128.         {  
  129.             UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();  
  130.             int userId=context.UserInfo.Max<UserInfo>(item => item.UserID);  
  131.             return userId;  
  132.         }  
  133.     }  
  134. }  
 
 说明,在上面的代码中每个方法的第一句都是实例化一个叫UserInfoDataClassesDataContext的类,这个类我们并没有编写,但是奇怪的是上面的代码居然能编译通过,这是为什么呢?原来秘密还是在那个dbml文件中,这个类在dbml的设计文件中的定义如下:
 可以看出UserInfoDataClassesDataContext是继承DataContext的,这个DataContext在MSDN中的定义为:

[c-sharp]  view plain copy
  1. [System.Data.Linq.Mapping.DatabaseAttribute(Name="AspNetStudy")]  
  2. public partial class UserInfoDataClassesDataContext : System.Data.Linq.DataContext  
  3. {  
  4. //.....省略其它代码  
  5. }  
 
 DataContext 是通过数据库连接映射的所有实体的源。它会跟踪您对所有检索到的实体所做的更改,并且保留一个“标识缓存”,该缓存确保使用同一对象实例表示多次检索到的实体。
 也就是我们用DataContext来与数据库进行交互,DataContext会根据上下文环境来决定如何与数据库交互,正因为如此,所以我们用Linq to SQL的代码才如此简单!
 三、单元测试代码

[c-sharp] view plaincopy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using NUnit.Framework;  
  6. using LinqDemo;  
  7.   
  8. namespace NUnitTest  
  9. {  
  10.     [TestFixture]  
  11.     public class LinqTest  
  12.     {  
  13.         private LinqCRUD instance = null;  
  14.         [SetUp]  
  15.         public void Initialize()  
  16.         {  
  17.             instance = new LinqCRUD();  
  18.         }  
  19.         [Test]  
  20.         /// <summary>  
  21.         /// 统计用户总数  
  22.         /// </summary>  
  23.         /// <returns></returns>  
  24.         public void Count()  
  25.         {  
  26.             Assert.Greater(instance.Count(), 0);  
  27.         }  
  28.         [Test]  
  29.         /// <summary>  
  30.         /// 创建用户  
  31.         /// </summary>  
  32.         /// <param name="info">用户实体</param>  
  33.         /// <returns></returns>  
  34.         public void Create()  
  35.         {  
  36.             UserInfo info = new UserInfo()  
  37.             {  
  38.                 Age = 12,  
  39.                 Email = "zzz@ccav.com",  
  40.                 Mobile = "13812345678",  
  41.                 Phone = "01012345678",  
  42.                 RealName = "测试" + DateTime.Now.Millisecond.ToString(),  
  43.                 Sex = true,  
  44.                 UserName = "zhoufoxcn" + DateTime.Now.Millisecond.ToString()  
  45.             };  
  46.             instance.Create(info);  
  47.         }  
  48.         [Test]  
  49.         /// <summary>  
  50.         /// 读取用户信息  
  51.         /// </summary>  
  52.         /// <param name="userId">用户编号</param>  
  53.         /// <returns></returns>  
  54.         public void Read()  
  55.         {  
  56.             UserInfo info = instance.Read(1);  
  57.             Assert.NotNull(info);  
  58.         }  
  59.         [Test]  
  60.         /// <summary>  
  61.         /// 更新用户信息  
  62.         /// </summary>  
  63.         /// <param name="info">用户实体</param>  
  64.         /// <returns></returns>  
  65.         public void Update()  
  66.         {  
  67.             UserInfo info = instance.Read(1);  
  68.             info.RealName = "测试" + DateTime.Now.Millisecond.ToString();  
  69.             instance.Update(info);  
  70.         }  
  71.         [Test]  
  72.         /// <summary>  
  73.         /// 删除用户  
  74.         /// </summary>  
  75.         /// <param name="userId">用户编号</param>  
  76.         /// <returns></returns>  
  77.         public void DeleteByID()  
  78.         {  
  79.             int userId = instance.GetMaxUserId();  
  80.             instance.Delete(userId);  
  81.         }  
  82.   
  83.         [Test]  
  84.         /// <summary>  
  85.         /// 删除用户  
  86.         /// </summary>  
  87.         /// <param name="userId">用户实体</param>  
  88.         /// <returns></returns>  
  89.         public void Delete()  
  90.         {  
  91.             int userId = instance.GetMaxUserId();  
  92.             UserInfo info = instance.Read(userId);  
  93.             //Console.WriteLine("MaxUserId=" + userId);  
  94.             instance.Delete(info);  
  95.         }  
  96.     }  
  97. }  
 
 上面的代码在NUnit2.5.3中测试通过。
 四、总结
 NHibernate与ADO.NET相比开发更简单,应对数据库的变化更灵活,而Linq to SQL比NHibernate更方便应对数据库变化,开发效率也高,使用Linq to SQL后我们仅需要编写一个类就足够了,比较遗憾的是Linq to SQL只支持SQL Server,所以很多人都在使用Entity Framework这个ORM框架了。下一篇就要讲述ADO.NET Entity Framework的用法了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值