原文地址

http://blog.csdn.net/zhoufoxcn/article/details/5402511

说明:个人感觉在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。
在本篇周公将讲述如何利用NHibernate实现CRUD功能,为了便于对比,在本次中采用与上次同样的数据库和表,并且也实现同样的功能。NHibernate是一个ORM框架,所谓ORM就是Object Relational Mapping,是一种将关系型数据库中的数据与面向对象语言中对象建立映射关联的技术,我们可以想操作对象一样操作数据,NHibernate将我们对对象的变更保存到数据库中去,并且还负责以对象的方式从数据库中查询数据,这样就可以使开发人员从处理SQL和ADO.NET上节省一些时间和精力用于处理业务逻辑。
1、准备
首先我们需要从网上下载NHibernate框架,这个可以到它的官方网站www.nhibernate.org上去下载,在周公写这篇文章的时候从网上能下载到的最新版本为2.1.2.GA。如果下载的是压缩包,请将压缩包解压,将会看到四分文件夹,它们的名称和作用分别如下:
Configuration_Templates:存放NHibernate连接数据库的配置文件的示例,在这个文件夹下分别有连接Firebird、SQL Server、MySQL、Oracle、PostgreSQL和SQLite数据库的配置示例,可以根据实际所使用的数据库选择示例中的代码并更改其中的数据源即可。
Required_Bins:存放NHibernate运行过程中所需要的类库文件,其中还包含了第三方的开源日志框架Log4Net,在不确定到底会使用那些类库的条件下建议将这个文件夹下所有的dll文件拷贝到项目的bin文件夹下。
Required_For_LazyLoading:存放延时加载特性支持所需的框架文件,在这个文件夹下提供了三种实现,选择一种将其下所有的dll文件拷贝到项目所在的bin文件夹下。在本示例中选择了Castle。
Tests:存放测试用文件,在此文件夹下还有一个名为ABC.hbm.xml的文件,这是一个数据表对应的配置文件的示例,在这个文件夹下的文件我们都用不着,不过在以后我们会用到.hbm.xml文件。
2、创建项目
我们创建一个项目,项目类型可以根据情况选择,因为我今后要使用NUnit来对项目进行单元测试,所以创建的类库项目。
创建项目成功之后将如下文件拷贝到项目的bin目录下:
Antlr3.Runtime.dll
Castle.Core.dll
Castle.DynamicProxy2.dll
Iesi.Collections.dll
log4net.dll
NHibernate.ByteCode.Castle.dll
NHibernate.dll
然后在项目中添加对这些dll的引用,如下图所示:
 
3、编写代码
3.1创建NHibernate配置文件
NHibernate的配置文件有相对比较固定的格式,这个可以从下载到框架文件压缩包解压得到,位于Configuration_Templates文件夹下。
向当前项目添加一个名为hibernate.cfg.xml的xml文件,在周公的机器上这个文件的格式内容如下:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
  3. <session-factory>
  4. <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
  5. <property name="connection.connection_string">
  6. Data Source=zhou;Initial Catalog=AspNetStudy;User ID=sa;Password=jerry;
  7. </property>
  8. <property name="adonet.batch_size">10</property>
  9. <property name="show_sql">true</property>
  10. <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
  11. <property name="use_outer_join">true</property>
  12. <property name="command_timeout">10</property>
  13. <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
  14. <property name="proxyfactory.factory_class">
  15. NHibernate.ByteCode.Castle.ProxyFactoryFactory,
  16. NHibernate.ByteCode.Castle
  17. </property>
  18. <mapping assembly="NHibernateDemo"/>
  19. </session-factory>
  20. </hibernate-configuration>

如果你也是使用SQL Server2005作为数据库的话,那么需要更改connection.connection_string中的数据库连接信息为你本机的连接信息,并且实际情况更改assembly的值为你当前项目编译后的程序集名称。
在这里还需要注意的是需要将hibernate.cfg.xml的属性更改为复制属性改为始终复制,如下图所示:
 
3.2创建映射文件
映射文件包含了对象/关系所需要的元数据,其中包含了所使用的持久化类和到数据库的映射。NHibernate就是通过映射文件知道怎样加载和存储持久化对象。
在项目中增加一个名为UserInfo.hbm.xml的xml文件,这个xml文件的内容如下:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateDemo" namespace="NHibernateDemo">
  3. <class name="UserInfo">
  4. <id name="UserId" column="UserId">
  5. <generator class="native"/>
  6. </id>
  7. <property name="UserName"/>
  8. <property name="RealName"/>
  9. <property name="Age"/>
  10. <property name="Sex"/>
  11. <property name="Mobile"/>
  12. <property name="Phone"/>
  13. <property name="Email"/>
  14. </class>
  15. </hibernate-mapping>

注意:如果想要获得在编辑hibernate.cfg.xml或者UserInfo.hbm.xml时的智能提示,可以将下载NHibernate压缩包中的nhibernate-configuration.xsd和nhibernate-mapping.xsd文件拷贝到VS的一个特殊文件夹中,在本机上周公在C盘安装了VS2008,那么需要将上面提到的文件拷贝到C:/Program Files/Microsoft Visual Studio 9.0/Xml/Schemas目录下,你需要根据你的实际情况来拷贝。
需要更改这个文件的属性,改为“嵌入的资源”,如下图所示:
 
3.3创建持久化类
在当前项目中创建一个名为UserInfo.cs的类文件,这个类的代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. namespace NHibernateDemo
  5. {
  6. /// <summary>
  7. /// 数据库中UserInfo表的持久化类
  8. /// 作者:周公
  9. /// 博客地址:http://blog.csdn.net/zhoufoxcn
  10. /// 日期:2010-03-19
  11. /// </summary>
  12. public class UserInfo
  13. {
  14. public virtual int UserId { get; set; }
  15. public virtual string UserName { get; set; }
  16. public virtual string RealName { get; set; }
  17. public virtual int Age { get; set; }
  18. public virtual bool Sex { get; set; }
  19. public virtual string Mobile { get; set; }
  20. public virtual string Phone { get; set; }
  21. public virtual string Email { get; set; }
  22. }
  23. }

注意:NHibernate通过使用属性的getter和setter操作来实现对象的持久化,并且要求类不能为sealed,方法和属性必须为virtual。
3.4编写辅助类
通过上面的文件NHibernate就可以实现关系映射了,这里编写相关的辅助类代码,如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using Iesi.Collections;
  5. using NHibernate;
  6. using NHibernate.Cfg;
  7. namespace NHibernateDemo
  8. {
  9. /// <summary>
  10. /// 说明:这个类是为了演示NHibernate中的CRUD的用法
  11. /// 作者:周公(周金桥)
  12. /// 日期:2010-03-07
  13. /// </summary>
  14. public class NHibernateCRUD
  15. {
  16. private ISessionFactory sessionFactory;
  17. public NHibernateCRUD()
  18. {
  19. sessionFactory = new Configuration().Configure().BuildSessionFactory();
  20. }
  21. public ISession GetSession()
  22. {
  23. return sessionFactory.OpenSession();
  24. }
  25. /// <summary>
  26. /// 统计用户总数
  27. /// </summary>
  28. /// <returns></returns>
  29. public int Count()
  30. {
  31. #region 方法一
  32. //ISession session = GetSession();
  33. //ISQLQuery query = session.CreateSQLQuery("select count(1) from UserInfo");
  34. //int count = query.List<int>()[0];
  35. //session.Close();
  36. //return count;
  37. #endregion
  38. #region 方法二
  39. ISession session = GetSession();
  40. IQuery query = session.CreateQuery("select count(c.UserId) from UserInfo c");
  41. //注意:不能对于count函数不能使用query.List<int>(),因为默认返回的数值类型是long
  42. //否则会抛出GenericADOException,异常描述是:Could not execute query[SQL: SQL not available]
  43. //InnerException: System.ArgumentException,InnerException描述是:"值“*”不是“System.Int32”类型,不能在此泛型集合中使用。/r/n参数名: value
  44. int count =(int)(query.List<long>()[0]);
  45. session.Close();
  46. return count;
  47. #endregion
  48. }
  49. /// <summary>
  50. /// 创建用户
  51. /// </summary>
  52. /// <param name="info">用户实体</param>
  53. /// <returns></returns>
  54. public int Create(UserInfo info)
  55. {
  56. ISession session = GetSession();
  57. int newId=(int)(session.Save(info));
  58. session.Flush();
  59. session.Close();
  60. return newId;
  61. }
  62. /// <summary>
  63. /// 读取用户信息
  64. /// </summary>
  65. /// <param name="userId">用户编号</param>
  66. /// <returns></returns>
  67. public UserInfo Read(int userId)
  68. {
  69. ISession session = GetSession();
  70. UserInfo info=session.Get<UserInfo>(userId);
  71. session.Close();
  72. return info;
  73. }
  74. /// <summary>
  75. /// 更新用户信息
  76. /// </summary>
  77. /// <param name="info">用户实体</param>
  78. /// <returns></returns>
  79. public void Update(UserInfo info)
  80. {
  81. ISession session = GetSession();
  82. session.Update(info);
  83. session.Flush();
  84. session.Close();
  85. }
  86. /// <summary>
  87. /// 删除用户
  88. /// </summary>
  89. /// <param name="userId">用户编号</param>
  90. /// <returns></returns>
  91. public void Delete(int userId)
  92. {
  93. ISession session = GetSession();
  94. //在NHibernate中支持直接使用参数值、":"+参数名、?(类似于在Access中使用参数化SQL语句的方式,给参数赋值要按照参数出现的顺序来)等几种方式
  95. IQuery query = session.CreateQuery("delete from UserInfo where UserId=:UserId");
  96. //如果采用":"+参数名方式使用参数,那么给参数赋值时不需要在参数名前加":"号,如query.SetInt32(":UserId", userId);就会报错
  97. query.SetInt32("UserId", userId);
  98. int affectedRows = query.ExecuteUpdate();
  99. session.Close();
  100. //return affectedRows;
  101. }
  102. /// <summary>
  103. /// 删除用户
  104. /// </summary>
  105. /// <param name="userId">用户实体</param>
  106. /// <returns></returns>
  107. public void Delete(UserInfo info)
  108. {
  109. ISession session = GetSession();
  110. session.Delete(info);
  111. session.Flush();
  112. session.Close();
  113. }
  114. /// <summary>
  115. /// 获取用户表中编号最大的用户
  116. /// </summary>
  117. /// <returns></returns>
  118. public int GetMaxUserId()
  119. {
  120. ISession session = GetSession();
  121. IQuery query=session.CreateQuery("select max(UserId) from UserInfo");
  122. int userId=query.List<int>()[0];
  123. session.Close();
  124. return userId;
  125. }
  126. }
  127. }

3.5单元测试代码

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using NUnit.Framework;
  6. using NHibernateDemo;
  7. namespace NUnitTest
  8. {
  9. [TestFixture]
  10. public class NHibernateTest
  11. {
  12. private NHibernateCRUD instance = null;
  13. [SetUp]
  14. public void Initialize()
  15. {
  16. instance = new NHibernateCRUD();
  17. }
  18. [Test]
  19. /// <summary>
  20. /// 统计用户总数
  21. /// </summary>
  22. /// <returns></returns>
  23. public void Count()
  24. {
  25. Assert.Greater(instance.Count(), 0);
  26. }
  27. [Test]
  28. /// <summary>
  29. /// 创建用户
  30. /// </summary>
  31. /// <param name="info">用户实体</param>
  32. /// <returns></returns>
  33. public void Create()
  34. {
  35. UserInfo info = new UserInfo()
  36. {
  37. Age = 12,
  38. Email = "zzz@ccav.com",
  39. Mobile = "13812345678",
  40. Phone = "01012345678",
  41. RealName = "测试" + DateTime.Now.Millisecond.ToString(),
  42. Sex = true,
  43. UserName = "zhoufoxcn" + DateTime.Now.Millisecond.ToString()
  44. };
  45. instance.Create(info);
  46. }
  47. [Test]
  48. /// <summary>
  49. /// 读取用户信息
  50. /// </summary>
  51. /// <param name="userId">用户编号</param>
  52. /// <returns></returns>
  53. public void Read()
  54. {
  55. UserInfo info = instance.Read(1);
  56. Assert.NotNull(info);
  57. }
  58. [Test]
  59. /// <summary>
  60. /// 更新用户信息
  61. /// </summary>
  62. /// <param name="info">用户实体</param>
  63. /// <returns></returns>
  64. public void Update()
  65. {
  66. UserInfo info = instance.Read(1);
  67. info.RealName = "测试" + DateTime.Now.Millisecond.ToString();
  68. instance.Update(info);
  69. }
  70. [Test]
  71. /// <summary>
  72. /// 删除用户
  73. /// </summary>
  74. /// <param name="userId">用户编号</param>
  75. /// <returns></returns>
  76. public void DeleteByID()
  77. {
  78. int userId = instance.GetMaxUserId();
  79. instance.Delete(userId);
  80. }
  81. [Test]
  82. /// <summary>
  83. /// 删除用户
  84. /// </summary>
  85. /// <param name="userId">用户实体</param>
  86. /// <returns></returns>
  87. public void Delete()
  88. {
  89. int userId = instance.GetMaxUserId();
  90. UserInfo info = instance.Read(userId);
  91. Console.WriteLine("MaxUserId=" + userId);
  92. instance.Delete(info);
  93. }
  94. }
  95. }

4.点评
使用ORM的很大的一个好处就是很少或者根本不用编写数据库记录映射到对象的代码,并且在大部分情况下也不用编写SQL代码(取而代之的是HSQL)。在使用ADO.NET时代我经常有这样的体会,因为数据库的变动可能需要更改从显示到数据库访问层的相关代码,并且还需要更改自己编写的从数据库记录转换为对象的代码,而现在仅仅需要更改映射文件和持久化类的代码就可以了,除此之外我们还可以使用面向对象的方式对数据进行操作,大家可以看到在NHibernateCRUD中对数据库进行CRUD的代码比直接使用ADO.NET进行CRUD操的代码要简洁许多,这就是ORM的魅力。
当然使用ORM也会存在一些缺点,毕竟ORM在底层使用的是ADO.NET,对于一个有经验的开发人员来说,可能直接使用ADO.NET的性能比使用NHibernate的效率要高,通过NHibernate的缓存机制多少能在某种程度上缓解这个问题。不过当数据量在千万级左右时这个问题就显得比较突出了,在一些数据量在百万级以下的情况中,合理使用NHibernate是没有什么问题的。

ADO.NET与ORM的比较:NHibernate实现CRUD(转)的更多相关文章

  1. 【转载】ADO.NET与ORM的比较(2):NHibernate实现CRUD

    [转载]ADO.NET与ORM的比较(2):NHibernate实现CRUD  转自周公 说明:个人感觉在Java领域大型开发都离不了ORM的身影,所谓的SSH就是Spring+Struts+Hibe ...

  2. 【转载】ADO.NET与ORM的比较(4):EntityFramework实现CRUD

    [转载]ADO.NET与ORM的比较(4):EntityFramework实现CRUD 说明:个人感觉在Java领域大型开发都离不了ORM的身影,所谓的SSH就是Spring+Struts+Hiber ...

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

    [转载]ADO.NET与ORM的比较(3):Linq to SQL实现CRUD 说明:个人感觉在Java领域大型开发都离不了ORM的身影,所谓的SSH就是Spring+Struts+Hibernate ...

  4. ORM武器:NHibernate(三)五个步骤+简单对象CRUD+HQL

    前面的两篇文章中.我们对NHibernate已经做了大致了解 <ORM利器:NHibernate(一)简单介绍>Nhibernate的作用:攻克了对象和数据库的转化问题 <ORM利器 ...

  5. .NET ORM框架之NHibernate

    这段时间一直使用NHibernate,今天抽空总结一下. 1.什么是NHibernate? NHibernate是一个面向.NET环境的对象/关系数据库映射工具.对象/关系数据库映射(object/r ...

  6. python-django使用ORM模型增删改查CRUD

    from weibo.models import WeiboUser as User user_obj = User.objects.get(pk=1) user_obj.pk Out[4]: 1 u ...

  7. Entity Framework与ADO.Net及NHibernate的比较

    Entity Framework  是微软推荐出.NET平台ORM开发组件, EF相对于ado.net 的优点 (1)开发效率高,Entity Framework的优势就是拥有更好的LINQ提供程序. ...

  8. ado.net与各种orm操作数据方式的比较

    ADO.NET与ORM的比较(1):ADO.NET实现CRUD http://zhoufoxcn.blog.51cto.com/792419/283952 ADO.NET与ORM的比较(2):NHib ...

  9. EF、Dapper、NHibernate等ORM框架的比较及优缺点

    什么是ORM? ORM的全称是Object Relational Mapping,即对象关系映射.它的实现思想就是将关系数据库中表的数据映射成为对象,以对象的形式展现,这样开发人员就可以把对数据库的操 ...

随机推荐

  1. spa 单页面解决浏览器back front 问题

    1.angular router reloadOnSearch:true(default) | false  默认为true,当url的hash发生改变,页面新渲染,component会重新加载(初始 ...

  2. Android的系统体系结构

    目录: Android的系统体系结构 Android的四种常用组件 Activity的启动流程 Android的系统体系结构 在入门了一个简单的Android的Hello World以后,我们首先来看 ...

  3. 【图像】Matlab图像标定工具箱

    参考教程: Matlab工具箱教程  http://www.vision.caltech.edu/bouguetj/calib_doc/ 摄像机模型  http://oliver.zheng.blog ...

  4. mysql授权

    grant all privileges on testdb to userA@'%' 然而通过userA登录查看存储过程时仍然无权限查看,通过jdbc连接程序也报错, 之前mysql在windows ...

  5. CSS+Javascript

    今天做了一个简单的CSS和Javascript的调用,发现CSS和Javascript系统的来写还真是蛮方便的. 1.先建一个CSS文件和一个JS文件 2.在jsp中调用 <link type= ...

  6. AxureRP8实战手册(基础21-30)

    AxureRP8实战手册(基础21-30) 本文目录 基础21.     设置元件默认选中/禁用 基础22.     设置单选按钮唯一选中 基础23.     设置元件不同状态时的样式 基础24.   ...

  7. MySQL问题记录--python插入中文至MySQL提示SQLErroor:1366错误

    一.在爬虫脚本做以下操作仍提示错误:SQL Error: 1366: Incorrect string value: "\xd0\xc2\xce\xc5-" for column  ...

  8. DOM操作方法的简单归纳

    (1)要在每个匹配的元素中插入新元素,使用: .append() .appendTo()   .prepend() .prependTo() (2)要在每个匹配的元素相邻的位置上插入新元素,使用: . ...

  9. 基础算法之冒泡排序Bubble Sort

    原理 将相邻的数据两两进行比较,按照从小到大或者从大到小的顺序进行位置交换,这样一趟过去后,最大或最小的数字被交换到了最后一位,然后从头开始再次进行两两比较交换,直到倒数第二位时结束.按照此规则,若干 ...

  10. 虚拟化--IO虚拟化基本原理

    本文话题: IO虚拟化概述 设备发现 访问截获 设备模拟 设备共享基于软件的IO虚拟化 基于前端后端的IO虚拟化基于硬件的IO虚拟化 概述 从处理器的角度看,外设是通过一组I/O资源(端口I/O或者是 ...