一、NHibernate简介
什么是?NHibernate?NHibernate是一个面向.NET环境的对象/关系数据库映射工具。对象/关系数据库映射(object/relational mapping,ORM)这个术语表示一种技术,用来把对象模型表示的对象映射到基于SQL的关系模型数据结构中去。
在今日的企业环境中,把面向对象的软件和关系数据库一起使用可能是相当麻烦和浪费时间的。而NHibernate不仅仅管理.NET类到数据库表的映射(包括.NET 数据类型到SQL数据类型的映射),还提供数据查询和获取数据的方法,可以大幅度减少开发时人工使用SQL和ADO.NET处理数据的时间。
NHibernate的目标主要是用于与数据持久化相关的编程任务,能够使开发人员从原来枯燥的SQL语句的编写中解放出来,解放出来的精力可以让开发人员投入到业务逻辑的实现上。对于以数据为中心的程序,开发人员往往是在数据库中使用存储过程来实现商业逻辑,这种情况下NHibernate可能不是最好的解决方案,但对于那些基于.NET,并且能够实现OO业务模型和商业逻辑的中间层应用,NHibernate是最有用的。NHibernate可以帮助用户消除或者包装那些针对特定厂商的SQL代码,并且帮用户把结果集从表格式的表示形式转换成一系列的对象。
NHibernate是一个目前应用的最广泛的开放源代码的对象关系映射框架,它对Java的JDBC(类似于ADO.Net)进行了非常轻量级的对象封装,使得程序员可以随心所欲的使用对象编程思维来操纵数据库,目前在国内Java开发界已经颇为流行,Hibernate+Spring往往是很多Java公司招聘的要求。而NHibernate,顾名思义,如同NUnit,NAnt一样,是基于.Net的Hibernate实现,但是目前介绍NHibernate的资料非常少,缺少一个系统完整的教程来全面的展现和深入NHibernate,而且现在NHibernate的文档又残缺不全,少的可怜,很多NHibernate的学习者往往都是通过Hibernate的文档来学习,但是毕竟不是所有的.Net开发者都熟悉Java,也不是所有的人都有精力有时间去学习Java,所以,我准备开始一个Step by Step的NHibernate教程,以便有兴趣的朋友能够快速的熟悉NHibernate,能够更快地体验NHibernate的开发乐趣。
NHibernate 是一个基于.Net 的针对关系型数据库的对象持久化类库。NHibernate 来源于非常优秀的基于Java的Hibernate 关系型持久化工具。
NHibernate 从数据库底层来持久化你的.Net 对象到关系型数据库。NHibernate 为你处理这些,远胜于你不得不写SQL去从数据库存取对象。你的代码仅仅和对象关联,NHibernat 自动产生SQL语句,并确保对象提交到正确的表和字段中去。
二、ORM简介
什么是ORM?对象-关系映射(Object/Relation Mapping,简称ORM),是随着面向对象的软件开发方法发展而产生的。面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。
面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的,两套理论存在显著的区别。为了解决这个不匹配的现象,对象关系映射技术应运而生。
让我们从O/R开始。字母O起源于”对象”(Object),而R则来自于”关系”(Relational)。几乎所有的程序里面,都存在对象和关系数据库。在业务逻辑层和用户界面层中,我们是面向对象的。当对象信息发生变化的时候,我们需要把对象的信息保存在关系数据库中。
如果打开你最近的程序(如,PetShop4.0),看看DAL(数据库访问层)代码,你肯定会看到很多近似的通用的模式。我们以保存对象的方法为例,你传入一个对象,为SqlCommand对象添加SqlParameter,把所有属性和对象对应,设置SqlCommand的CommandText属性为存储过程,然后运行SqlCommand。对于每个对象都要重复的写这些代码。除此之外,还有更好的办法吗?有,引入一个O/R Mapping。实质上,一个O/R Mapping会为你生成DAL。与其自己写DAL代码,不如用O/R Mapping。你用O/R Mapping保存,删除,读取对象,O/R Mapping负责生成SQL,你只需要关心对象就好。
三、NHiberante的优缺点
3.1 优点
(1).面向对象:NHiberante的使用时只需要操纵对象,使开发更对象化,抛弃了数据库中心的思想,完全的面向对象思想。
(2).透明持久化:带有持久化状态的、具有业务功能的单线程对象,此对象生存期很短。这些对象可能是普通的POCO,这个对象没有实现第三方框架或者接口,唯一特殊的是他们正与(仅仅一个)Session相关联。一旦这个Session被关闭,这些对象就会脱离持久化状态,这样就可被应用程序的任何层自由使用。(例如,用作跟表示层打交道的数据传输对象。)
(3).它没有侵入性,即所谓的轻量级框架。正因为它具有透明持久化的优点,它才没有侵入性,才是一个轻量级框架。恒定一个框架为重量级、还是轻量级,是根据其侵入性而定夺的。而NHibernate就是一个轻量级ORM框架。
(4).较好的移植性:支持多种数据库,便于数据库的迁移。
(5).缓存机制:提供一、二级缓存和查询缓存。
(6).开发效率:众所周知,使用NHibernate可以简化程序开发,从而达到快速开发的目的。作为软件公司,项目管理的关键就是控制开发成本。正因为使用NHibernate后所写的代码量减少了,相对于原先使用“SqlHelper、DAL、BLL”开发程序的项目周期缩短了,成本就降低了。
3.2 缺点
(1).内存消耗:直接使用“SqlHelper、DAL、BLL”无疑是最省内存的。使用NHibernate后,内存开销比较大,这点是毋庸置疑的。
(2).批量数据库的处理:由于NHibernate是基于面向对象的ORM框架,处理数据库的方式是针对单个对象的。对数据库的增、删、改都是正对一条记录而言。对于批量修改、删除数据,不适合用NHiberante。这也是所有OR框架弱点,其原因,我认为是在于与缓存机制的冲突。
(3).较多使用数据库特性时,也不适合使用NHiberante。如数据库中大量的存储过程、触发器、特点的SQL语句。
(4).表关系比较混乱时也不适合使用NHiberante。NHibernate只适合于表与表的关系比较明确的环境中。如本应该建立外键的,没有建立外键。这时使用NHiberante不仅没有减少工作量,反而增加了工作量。
(5).学习成本:相对于NHibernate来说,使用“SqlHelper、DAL、BLL”操作数据库,学习成本比较低,而且上手很快。使用NHibernate需要有一定OOP(面向对象编程)和OOD(面向对象设计)的基础,这对于基础薄弱的程序员来说,从面向过程的编程到面向对象的编程,需要一定的投入;一般情况下需要学习1个月左右的时间才能够深入NHiberante。
四、简单增删改查
1、创建MVC项目,并创建相关类
2、安装NHibernate4.0
3、配置NHibernate
将下图中花圈的文件复制到Shop.Web项目中,放在主目录下面,因为我使用的是Sql Server
然后重命名为Hibernate.cfg.xml
为Hibernate.cfg.xml文件添加mapping节点
<?xml version="1.0" encoding="utf-8"?>
<!--
This template was written to work with NHibernate.Test.
Copy the template to your NHibernate.Test project folder and rename it in hibernate.cfg.xml and change it
for your own use before compile tests in VisualStudio.
-->
<!-- This is the System.Data.dll provider for SQL Server -->
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory name="NHibernate.Test">
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string">
Server=.\MSSQL2008R2;database=TEST;uid=sa;pwd=123456
</property>
<!--NHibernate方言(Dialect)的类名 - 可以让NHibernate使用某些特定的数据库平台的特性-->
<property name="dialect">NHibernate.Dialect.MsSql2012Dialect</property>
<!--在控制台显示SQL-->
<property name="show_sql">true</property>
<!--指定映射文档中所在程序集-->
<mapping assembly="Shop.Domain"/>
</session-factory>
</hibernate-configuration>
修改Hibernate.cfg.xml文件属性为始终复制或者如果较新则复制
4、在Shop.Data项目中创建NHibernateHelper帮助类
namespace Shop.Data
{
public class NHibernateHelper
{
private static ISessionFactory _sessionFactory;
public static ISessionFactory SessionFactory
{
get
{
//配置ISessionFactory
return _sessionFactory == null ? (new Configuration()).Configure().BuildSessionFactory() : _sessionFactory;
}
}
}
}
5、在Shop.Domain项目中创建Customers实体类
namespace Shop.Domain.Entities
{
public class Customers
{
public virtual int CustomerID { get; set; }
public virtual string CompanyName { get; set; }
public virtual string ContactName { get; set; }
public virtual string ContactTitle { get; set; }
public virtual string Address { get; set; }
public virtual string City { get; set; }
public virtual string Region { get; set; }
public virtual string PostalCode { get; set; }
public virtual string Country { get; set; }
public virtual string Phone { get; set; }
public virtual string Fax { get; set; }
}
}
6、在Shop.Domain项目中新建Customers.hbm.xml作为Customers持久化类的映射文件
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Shop.Domain" namespace="Shop.Domain.Entities">
<class name="Shop.Domain.Entities.Customers,Shop.Domain" table="Customers">
<id name="CustomerID" column="CustomerID" type="int"></id>
<property name="CompanyName" column="CompanyName" type="string"></property>
<property name="ContactName" column="ContactName" type="string"></property>
<property name="ContactTitle" column="ContactTitle" type="string"></property>
<property name="Address" column="Address" type="string"></property>
<property name="City" column="City" type="string"></property>
<property name="Region" column="Region" type="string"></property>
<property name="PostalCode" column="PostalCode" type="string"></property>
<property name="Country" column="Country" type="string"></property>
<property name="Phone" column="Phone" type="string"></property>
<property name="Fax" column="Fax" type="string"></property>
</class>
</hibernate-mapping>
设置文件属性
7、在Shop.Data中添加数据访问类CustomersData,编写GetCustomerList方法 获取所有客户列表
public IList<Customers> GetCustomerList(Expression<Func<Customers,bool>> where)
{
try
{
using(ISession session = NHibernateHelper.SessionFactory.OpenSession())
{
return session.Query<Customers>().Select(x => new Customers
{
CustomerID = x.CustomerID,
ContactName = x.ContactName,
ContactTitle = x.ContactTitle,
City = x.City,
Address = x.Address,
Phone = x.Phone,
CompanyName = x.CompanyName,
Country = x.Country,
Fax = x.Fax,
Region=x.Region,
PostalCode=x.PostalCode
}).Where(where).ToList();
}
}
catch (Exception ex)
{
throw ex;
}
}
8、添加业务逻辑层,在Shop.Business项目中新建CustomersBusiness类
public class CustomersBusiness
{
private CustomersData _customersData;
public CustomersBusiness()
{
_customersData = new CustomersData();
}
public IList<Customers> GetCustomersList(Expression<Func<Customers, bool>> where)
{
return _customersData.GetCustomerList(where);
}
}
9、添加控制器,添加视图
public class CustomersController : Controller
{
CustomersBusiness customersBusiness = new CustomersBusiness();
// GET: Customers
public ActionResult Index()
{
var result = customersBusiness.GetCustomersList(c => 1 == 1);
return View(result);
}
}
10、显示结果
11、增删改查
public Customers GetByID(int id)
{
using(ISession session = NHibernateHelper.SessionFactory.OpenSession())
{
Customers customers = session.Get<Customers>(id);
return customers;
}
}
public bool Insert(Customers customer)
{
using (ISession session = NHibernateHelper.SessionFactory.OpenSession())
{
var identifier = session.Save(customer);
session.Flush();
return string.IsNullOrEmpty(identifier.ToString());
}
}
public void Update(Customers customer)
{
using (ISession session = NHibernateHelper.SessionFactory.OpenSession())
{
session.SaveOrUpdate(customer);
session.Flush();
}
}
public void Delete(int id)
{
using (ISession session = NHibernateHelper.SessionFactory.OpenSession())
{
Customers customer = session.Get<Customers>(id);
session.Delete(customer);
session.Flush();
}
}