DataAccess是一個DAO架構,可以通過設定檔配置應用程式使用的DAO實現,並且自己提供了幾個具體資料訪問方式的封裝,以簡化DAO實現層開發。
DataAccess的原始碼相對於DataMapper要簡單的多。
一.關鍵類
1.Configuration目錄
定義了DataAccess的模型,該模型和xml設定檔對應,因此該目錄同時提供了從xml設定檔解析為DataAccess物件模型和將物件模型序列化為xml檔案的功能。
2.Exceptions目錄
Exceptions目錄中只有一個DataAccessException異常類。DataAccess架構產生的異常會被封裝為該類。
3.Interfaces目錄
Interfaces目錄定義了兩個介面:IDao和IDaoSessionHandler。IDao是我們自己的DAO實作類別必須繼承的標誌介面。IDaoSessionHandler定義了不同會話處理器(SessionHandler)的通用介面。用於從配置Dao管理器相關的資訊,並擷取當前的DaoSession。
4.Scope目錄
維護當前的配置和錯誤資訊。
5.DaoSessionHandlers目錄
DaoSessionHandlers目錄包含對ADO.NET和SqlMap的封裝。比如SimpleDaoSession 是 An ADO.NET implementation of the DataAccess Session .SqlMapDaoSession 是 An SqlMappper implementation
of the DataAccess Session.這兩個類都實現了IDaoSession,用來處理會話相關的串連,事務等。SimpleDaoSessionHandler和SqlMapDaoSessionHandler類都實現了IDaoSessionHandler介面,用於從解析後的配置資訊中擷取DaoSession和其相關的配置。
6.主目錄
SessionHolder類和java中的ThreadLocal類似,為每個線程維護一個IDalSession。
DaoManager是一個Facade類,複雜讀取設定檔並初始化架構;為不同的context維護不同的配置資訊;提供訪問DAO實現的方法;提供訪問當前Session中的串連(connection)和事務(transaction)方法。
二.使用簡介和架構執行流程
DataAccess架構(圖略):
由於DataAccess可以和任何DAO實現工作,核心庫中提供了對ADO.NET和SqlMap(也就是DataMapper)的封裝,擴充庫中提供了對NHibernate的封裝,利用這些封裝編成很更簡單,更實用。DataAccess文檔上說:
if your application is using raw ADO, the DAO framework will hide classes like DataReader, DataAdapter, Connection, and Command. Similarly, if your application
is using the NHibernate object persistence library, the DAO framework will hide classes like Configuration, SessionFactory, Session, and HibernateException. All of these implementation details will be hidden behind a consistent DAO interface layer. Furthermore,
the number of different data sources that are being used can be hidden from the view of the application.
這裡只簡單介紹DataAccess和DataMapper配合使用,DataMapper的類和配置利用以上介紹的DataMapper中的例子。
DataAccess的使用需要以下幾個步驟:
1.設計DAO介面。
2.選擇一種DAO實現。
3.編寫dao.config設定檔。
4.利用DAO進行資料操作。
由於DataAccess架構要求每個DAO實作類別,必須實現IDao介面,即然利用DAO架構編程,我們必須定義自己的DAO介面。作為最佳實務可以這樣設計:
1).我們自己的DAO介面應該是和任何架構無關的,也就是我們的DAO介面不需要繼承自IDao介面,而且所有的DAO介面在一個或幾個項目中,最後打包為一個或幾個dll中,例如:
namespace dao{ public interface IProduct { IList GetProductList(); void UpdateProduct(Product pro); }}
2).設計一個BaseDao基類,該類封裝了一種具體的DAO實現的資料存取方法並且實現IDao標誌介面,例如我們利用SqlMapper作為資料持久層,BaseDao可以這樣設計:
namespace impl{ public class BaseDao : IDao { protected const int PAGE_SIZE = 4; /// /// Looks up the parent DaoManager, gets the local transaction /// (which should be a SqlMapDaoTransaction) and returns the /// SqlMap associated with this DAO. /// /// The SqlMap instance for this DAO. protected SqlMapper GetLocalSqlMap() { DomDaoManagerBuilder builder = new DomDaoManagerBuilder(); builder.Configure(); DaoManager daoManager = DaoManager.GetInstance(this); SqlMapDaoSession sqlMapDaoSession = (SqlMapDaoSession)daoManager.LocalDaoSession; return sqlMapDaoSession.SqlMap; } /// /// Simple convenience method to wrap the SqlMap method of the same name. /// Wraps the exception with a DataAccessException to isolate the SqlMap framework. /// /// /// /// protected IList ExecuteQueryForList(string statementName, object parameterObject) { SqlMapper sqlMap = GetLocalSqlMap(); try { return sqlMap.QueryForList(statementName, parameterObject); } catch (Exception e) { throw new DataAccessException("Error executing query '" + statementName + "' for list. Cause: " + e.Message, e); } } /// /// Simple convenience method to wrap the SqlMap method of the same name. /// Wraps the exception with a DataAccessException to isolate the SqlMap framework. /// /// /// /// /// /// protected IList ExecuteQueryForList(string statementName, object parameterObject, int skipResults, int maxResults) { SqlMapper sqlMap = GetLocalSqlMap(); try { return sqlMap.QueryForList(statementName, parameterObject, skipResults, maxResults); } catch (Exception e) { throw new DataAccessException("Error executing query '" + statementName + "' for list. Cause: " + e.Message, e); } } ................... }}
3).我們的具體DAO實作類別繼承自BaseDao,並實現自己的DAO介面。並利用BaseDao提供的基礎功能工作,而且所有的DAO實現在一個或幾個項目中,最後打包為一個或幾個dll中,這樣以後可以簡化維護並方便修改daofactory的配置,例如:
namespace impl{ public class ProductDAO : BaseDao, IProduct { #region IProduct Members public IList GetTheProductList() { IList prods = base.ExecuteQueryForList("getProduct", null); Console.WriteLine("public System.Collections.IList GetProductList():"); foreach (Product p in prods) { Console.WriteLine("id:{0};Org:{1};PlatId:{2}", p.Id, p.Org, p.PlatId); } return prods; } public void UpdateTheProduct(Product pro) { base.ExecuteUpdate("updateNews", pro); Console.WriteLine("public void UpdateProduct(Domain.Product pro) finished."); } #endregion }}
設定檔--dao.config
<?xml version="1.0" encoding="utf-8"?>
<daoConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
<providers resource="providers.config"/>
<context id="SqlMapDao" default="true">
<database>
<provider name="oracle9.2"/>
<dataSource name="ibatisDemo" connectionString="Data Source=DATA-89;Persist Security Info=True;User ID=data;password=data"/>
database>
<daoSessionHandlers>
<daoSessionHandler id="SqlMap">
<property name="resource" value="sqlMap.config"/>
daoSessionHandler>
daoSessionHandlers>
<daoFactory>
<dao interface="dao.IProduct,dao" implementation="impl.ProductDAO,impl"/>
daoFactory>
context>
daoConfig>
使用DAO實現操作資料儲存
namespace OraTest{ class Program { public static void Main() { //讀取設定檔建立DaoManager,並擷取SqlMapDao context執行個體。 DomDaoManagerBuilder builder = new DomDaoManagerBuilder(); builder.Configure(); DaoManager daoManager = DaoManager.GetInstance("SqlMapDao"); //擷取IProductDAO介面的具體實作類別,並初始化。 IProduct dao = daoManager[typeof(IProduct)] as IProduct; //利用DAO編程。 dao.GetProductList(); Product p = new Product(); p.Id = "FR20T0000003000000096426"; p.Org = "orgid2"; dao.UpdateProduct(p); } }}
有上可見,DAO架構為我們編程提供了極大的靈活性。並且可以在發布甚至運行時通過修改dao.config,改變DAO實現。