1、Nhibernate簡介
NHibernate是一個面向.NET環境的對象/關系數據庫映射工具。對象/關系數據庫映射(object/relational mapping,ORM)這個術語表示一種技術,用來把對象模型表示的對象映射到基於SQL的關系模型數據結構中去
簡單的說就是將數據庫的結構直接映射到實體模型之上,從而簡化SQL的數據處理時間。通過XML(Fluent亦可)進行定義數據模型的持久化,nhibernate 內部的映射結構以及如圖1-1所示:
2、准備
- Nhibernate類庫,下載直通車。壓縮包內部所下載版本的源碼,范例等。
- 配置Visual Studio的NHibernate配置的智能提示,從上一部下載包中找到configuration.xsd和nhibernate-mapping.xsd放置X:\Program Files\Microsoft Visual Studio X\Xml\Schemas
- Northwind數據庫(范例數據庫)也可以使其他的數據庫
- 建立NhibernateTest解決方案,目錄結構如圖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表進行讀寫數據
- 配置Northwind.cfg.xml數據庫的
<?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>
- Customers實體對象映射,包含實體對象以及對應的映射xml
這里有一點需要注意的:實體映射的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>
- 控制台調用,實現對Customers的基本操作
//數據庫配置文件完全地址 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 設計模式