Nhibernate + WCF + ASP.NET MVC + NVelocity 對PetShop4.0重構(三)——持久層
什麼是持久層?先解釋什麼是持久,英文persistence,將內存中的數據固化,保持在物理儲存設備中。然而在企業應用中,往往通過 關系型數據庫來完成這一過程。那麼持久層的定義是:相對於三層架構中的表示層、業務層而言,專門負責持久化數據的獨立領域。設 計模式中的“單一職責”原則確定了分層的目的,說白了,持久層就是專門與數據庫打交道的。如圖1所示
圖1
在PetShop4.0中的DAL(數據庫訪問層)就是操作數據庫的。在其DAL中,通過SQL語句返回DataReader,然後給Model對象賦值;在添加、 修改、刪除操作中,通過Model對象的數據生成SQL語句,然後寫入數據庫。此時,我們能夠看出每張表都用同樣的操作。雖然PetShop4.0 使用SqlHelper封裝數據庫操作,但是卻沒有一個通用的CRUD封裝。目前PetShop4.0每個表都對應各種的CRUD,這樣就會出現大量重復的代 碼。
對於PetShop4.0的使用多鐘數據庫來言。對於每種數據庫都要寫一種DAL。這樣數據庫的可移植性就不強了。
針對上述問題,我使用ORM框架NHibernate作為持久層框架,來取代PetShop4.0的DAL。
什麼是ORM?對象關系映射,英文Object Relational Mapping。是解決“阻抗不匹配”的一種技術。“阻抗不匹配”是指,關系型數據 庫中數據與編程語言中的對象存在差異。使用面向對象的語言編程的同時又要為“面向關系”而犯愁。在企業級的系統開發中,程序員有 30%的時間用來解決“阻抗不匹配”的問題,花大量時間去編寫SQL語句。而ORM框架的出現就能很好的解決這樣的問題,從而做到快速開發 。在一個項目的編碼過程中,業務層是比較重要的,則編寫表示層和持久層代碼所用的時間不應該過長。所以使用好一個ORM框架尤為重要 。至於為什麼要使用ORM框架,有一個重要的原因:提高開發速度,減少開發和維護成本。然而這一點對於一個商業公司來說相當看重。
ORM的O是對象的意思,代表高級語言中的實體(Entity)模型;R是關系的意思,代表關系型數據庫;M是映射的意思,表示通過某種方式 實現對象和關系型數據庫的映射。如圖2所示
圖2
本系列文章,使用NHibernate作為ORM框架。這樣操作對象就相當於操作數據庫,開發人員不需要關心SQL語句怎麼寫,一門心思的專注 面向對象的開發,從而使得應用程序更OO(面向對象)。作為NHibernate的實體對象,完全是POJO(上篇文章提到過)。在持久層中, NHibernate框架借助映射文件和實體所承載的數據自動生成SQL語句,實現自動持久化。但是NHibernate仍然存在一些缺點:如,批量刪除 和修改。至於復雜的查詢報表來說,java開發人員往往放棄Hibernate,而使用ibatis或jdbc的方式實現。但是.NET在這一點做的很好,通 過NHibernate集成Linq的方式,使我們能夠通過Linq的語法查詢出想要得到的數據。巧妙的把C#語法(更且卻的說是.NET)和java中最流行 的框架之一的.NET版NHibernate完美結合起來。可以這麼說,HQL(Hibernate Query Language)不是完全的面向對象,但是Linq to NHibernate是覺對的面向對象。
在調用NHibernate的API操作數據庫時,每個對象都需要寫一個DAO。這裡,我們使用基於泛型的Repository(資源庫)模式將相同的代碼 內聚起來。
IRepository
public interface IRepository<T> where T : class
{
/// <summary>
/// 獲取實體
/// </summary>
/// <param name="id">主鍵</param>
/// <returns></returns>
T Get(object id);
/// <summary>
/// 插入實體
/// </summary>
/// <param name="entity">實體</param>
/// <returns></returns>
object Save(T entity);
/// <summary>
/// 修改實體
/// </summary>
/// <param name="entity">實體</param>
/// <returns></returns>
void Update(T entity);
/// <summary>
/// 保存實體
/// </summary>
/// <param name="entity">實體</param>
/// <returns></returns>
void SaveOrUpdate(T entity);
/// <summary>
/// 刪除實體
/// </summary>
/// <param name="entity">實體</param>
/// <returns></returns>
void Delete(T entity);
/// <summary>
/// 獲取全部集合
/// </summary>
/// <returns></returns>
IQueryable<T> LoadAll();
}
RepositoryBase
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using Spring.Data.NHibernate.Generic.Support;
using NHibernate.Linq;
public abstract class RepositoryBase<T> : HibernateDaoSupport, IRepository<T> where T : class
{
public virtual object Save(T entity)
{
return this.HibernateTemplate.Save(entity);
}
public virtual T Get(object id)
{
return this.HibernateTemplate.Get<T>(id);
}
public virtual IQueryable<T> LoadAll()
{
return this.Session.Linq<T>();
}
public virtual void Update(T entity)
{
this.HibernateTemplate.Update(entity);
}
public void Delete(T entity)
{
this.HibernateTemplate.Delete(entity);
}
public virtual void SaveOrUpdate(T entity)
{
this.HibernateTemplate.SaveOrUpdate(entity);
}
}
這樣,同為增、刪、改、查的代碼,我只需要寫一遍就可以了。對於數據庫的遷移,可以通過配置數據庫方言來實現其目的。在使用 Spring.NET作為IoC框架中,我們不用關心和有意去編寫數據庫事務,並且NHibernate的Session管理也交給Spring.NET來處理。重構後的 代碼與PetShop4.0的DAL代碼比較起來,代碼行數減少了很多,但代碼的可維護性和靈活性卻有明顯的提升。