NHibernate是一个面向.NET环境的对象/关系数据库映射工具。对象/关系数据库映射(object/relational mapping,ORM)这个术语表示一种技术,用来把对象模型表示的对象映射到基于SQL的关系模型数据结构中去
简单的说就是将数据库的结构直接映射到实体模型之上,从而简化SQL的数据处理时间。通过XML(Fluent亦可)进行定义数据模型的持久化,nhibernate 内部的映射结构以及如图1-1所示:
2、准备
3、使用范例
NHibernate通过配置文件(app.config,web.config,db.cfg.xml)进行加载,从而得到ISessionFactory。一般而言,一个数据库保持一个ISessionFactory。ISessionFactory工厂进行创建ISession(Nhibernate工作单元)。ISession代表一次数据库的操作,一次操作之后需要对其进行关闭。
SessionFactory (NHibernate.ISessionFactory)
对属于单一数据库的编译过的映射文件的一个线程安全的,不可变的缓存快照。它是Session的工厂,是ConnectionProvider的客户。可以持有一个可选的(第二级)数据缓存,可以在进程级别或集群级别保存可以在事物中重用的数据。
会话,Session (NHibernate.ISession)
单线程,生命期短促的对象,代表应用程序和持久化层之间的一次对话。封装了一个ADO.NET连接。也是Transaction的工厂。保存有必需的(第一级)持久化对象的缓存,用于遍历对象图,或者通过标识符查找对象。
现在要实现针对Northwind数据库的Customers表进行读写数据
<?xml version="1.0" encoding="utf-8" ?> <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=.;initial catalog=Northwind;uid=sa;pwd=123456;Integrated Security=SSPI </property> <property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property> <property name="show_sql">true</property> <mapping assembly="nHibernateTest"/> </session-factory> </hibernate-configuration>
这里有一点需要 注意 的:实体映射的id列是必须的,否则会报错。一般在配置文件中设置三种:native(根据底层数据库的能力选择 identity, sequence 或者 hilo中的一个),assigned(自己指定),forign(使用另外一个相关联的对象的标识符,和<one-to-one>联合一起使用。 )
public class Customers:IAggregateRoot { public Customers() { } public virtual string 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; } }
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="nHibernateTest" namespace="nHibernateTest.Entity"> <class name="Customers" table="Customers"> <id name="CustomerID" column="CustomerID" type="String"> <generator class="assigned"/> </id> <property name="CompanyName" /> <property name="ContactName" /> <property name="ContactTitle" /> <property name="Address" /> <property name="City" /> <property name="Region" /> <property name="PostalCode" /> <property name="Country" /> <property name="Phone" /> <property name="Fax" /> </class> </hibernate-mapping>
//数据库配置文件完全地址 var dbConfigFullPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Northwind.cfg.xml"); //Hibernate加载数据库配置文件 var nHConfiguration = new NHibernate.Cfg.Configuration().Configure("Northwind.cfg.xml"); //获得session工厂 var sessionFactory = nHConfiguration.BuildSessionFactory(); using (var session = sessionFactory.OpenSession()) { var customer = new Customers() { CustomerID = "luge", CompanyName = "卤鸽", Address = "博客园", Phone = "123456" }; //插入数据 session.Save(customer); session.Flush(); //get是直接执行sql语句得到实体对象 var getCustomer = session.Get<Customers>("luge"); getCustomer.CompanyName = "飞鸽"; session.SaveOrUpdate(getCustomer); session.Flush(); //load主要在是需要调用的时候才进行执行sql语句 var loadCustomer = session.Load<Customers>("luge"); session.Delete(loadCustomer); session.Flush(); }
Northwind数据库中① 表Customers与表Orders是一对多关系② 表Customers与表CustomerDemographics表示多对多关系。
NHibernate针对集合进行映射的节点,(tip:由于笔者使用Nhibernate 4.0.3GA的最新版本,内部支持Net4.0的ISet<T>接口,并且已经去除了Iesi.Collections的引用)
<set>元素:它的元素存放没有顺序且不重复;
<list>元素:它需要在集合属性对应的数据库表中用一个额外的索引列保存每个元素的位置。
<bag>元素:它的元素可能重复,但不保存顺序
<map>元素:它的元素以键值对的形式保存,也是无序的,它的元素可以按自然顺序排序
Customers与Orders之间xml配置如下:
<!--Customers xml mapping --> <set name="Orders" generate="true"> <key column="CustomerID" /> <one-to-many class="Orders"/> </set> //Customers实体增加 //构造函数 public Customers() { Orders=new HashSet<Orders>(); } public virtual ISet<Orders> Orders{get;set;} <!--Orders xml mapping--> <many-to-one name="Customers" class="Customers" > <column name="CustomerID"/> </many-to-one> //Orders实体增加 public virtual Customers Customers{get;set;}
//多对多关系 <!--Customers xml mapping--> <set name="CustomerDemographics" table="CustomerCustomerDemo" schema="dbo" generic="true"> <key column="CustomerID" /> <many-to-many class="CustomerDemographics" fetch="join" column="CustomerTypeID"/> </set> //Customers实体,构造函数相应增加实例化 public virtual ISet<CustomerDemographics> CustomerDemographics{get;set;} <!--CustomerDemographics xml mapping--> <set name="Customers" table="CustomerCustomerDemo" > <key column="CustomerTypeID"/> <many-to-many class="Customers" fetch="join" column="CustomerID"/> </set> //CustomerDemographics实体增加实例化 public virtual ISet<Customers> Customers{get;set;}
4、扩展
针对具体项目使用时,一般对NHibernate进行封装。笔者这里抽象一个IRepositoryd<T,TEntity> 接口作为公用接口(本文内容只是范例,如若用于具体项目自行调整)
public interface IRepository<T, EntityKey> where T : IAggregateRoot { void Add(T entity); void Remove(T entity); void Save(T entity); T FindBy(EntityKey Id); IEnumerable<T> FindAll(); IEnumerable<T> FindAll(int index, int pageSize, out int count); IEnumerable<T> FindBy(IList<ICriterion> queryList, Order order); IEnumerable<T> FindBy(IList<ICriterion> queryList,Order order, int index,int pageSize,out int count); } public abstract class Repository<T, EntityKey> : IRepository<T, EntityKey> where T : IAggregateRoot { private IUnitOfWork _uow; public Repository(IUnitOfWork uow) { _uow = uow; } public void Add(T entity) { _uow.RegisterNew(entity); //throw new NotImplementedException(); } public void Remove(T entity) { _uow.RegisterRemoved(entity); //throw new NotImplementedException(); } public void Save(T entity) { _uow.RegisterAmended(entity); } public T FindBy(EntityKey Id) { return _uow.Session.Get<T>(Id); } public IEnumerable<T> FindAll() { return (List<T>)_uow.Session.CreateCriteria(typeof(T)).List(); } public IEnumerable<T> FindAll(int index, int pageSize, out int count) { ICriteria CriteriaQuery = _uow.Session.CreateCriteria(typeof(T)); index=(index>=1?index:1); var countCirteria = CriteriaQuery.Clone() as ICriteria; var futureCount = countCirteria.SetProjection(Projections.RowCount()).FutureValue<Int32>(); count = futureCount.Value; var queryList = CriteriaQuery.SetFirstResult((index-1)*pageSize).SetMaxResults(pageSize).List(); return (List<T>)queryList; } public IEnumerable<T> FindBy(IList<ICriterion> queryList, Order order) { //Restrictions.Eq("Category.Id", 2) 进行添加查询数据 ICriteria CriteriaQuery = _uow.Session.CreateCriteria(typeof(T)); foreach (var queryItem in queryList) { CriteriaQuery.Add(queryItem); } return CriteriaQuery.AddOrder(order).List<T>(); } /// <summary> /// /// </summary> /// <param name="queryList"></param> /// <param name="order"></param> /// <param name="index"></param> /// <param name="count"></param> /// <returns></returns> public IEnumerable<T> FindBy(IList<ICriterion> queryList, Order order, int index, int pageSize, out int count) { ICriteria CriteriaQuery = _uow.Session.CreateCriteria(typeof(T)); foreach (var queryItem in queryList) { CriteriaQuery.Add(queryItem); } var listByQuery = CriteriaQuery; var countCrieriaQuery = CriteriaQuery.Clone() as ICriteria; var rowCount = countCrieriaQuery.SetProjection(Projections.RowCount()).FutureValue<Int32>(); count = rowCount.Value; index = index >= 1 ? index : 1; return listByQuery.AddOrder(order).SetFirstResult((index - 1) * pageSize).SetMaxResults(pageSize).List<T>(); }
5、本文例子的源码下载
源码(如果觉得不错请点赞下,有误的话请指出,卤鸽在此感谢)
参考:
http://www.cnblogs.com/lyj/archive/2008/10/30/1323099.html
ASP.NET 设计模式