Android通用DAO(數據訪問對象)設計和實現

一、前言:


在Android的應用開發中,每每會涉及到許多數據的存儲和交互,其中,內嵌的sqlite數據庫會做爲首選的方案,在一些涉及比較多的數據交互情境中,一般表現爲表的數量比較多,咱們就有必要開發一個比較通用的數據訪問框架了。java

二、設計目標:

(1):可以方便地建立表和對象的對應關係.[這裏咱們以註解的方式實現]git

(2):可以以統一的方式方便的進行數據的增刪查改.sql

也就是可以使用相似Hibernate等框架的使用: 如增長一條記錄的使用習慣:數據庫

  TUser user = new TUser(); user.setId("id"); userDao.insert(user). 緩存

三、實現結果初體驗:


(1):描述表和對象關係:框架

@Table(name = "t_user")
public class TUser {

	@Column(name="user_id",type=Column.TYPE_BOOLEAN,isPrimaryKey=true)
	private Integer userId;
	
	@Column(name="user_name",type=Column.TYPE_STRING)
	private String userName;

	/**
	 * 必須提供無參構造函數
	 */
	public TUser() {}
	
	public TUser(String userName) {
		this.userName = userName;
	}
        
        //getter

        //setter 
	
}

(2):增刪查改函數


//Insert An Object
		IBaseDao<TUser> userDao = DaoFactory.createGenericDao(this, TUser.class);
		userDao.insert(new TUser("AAAA"));
		
		//Insert Object List
		List<TUser> insertUserList = new ArrayList<TUser>();
		for(int i = 0; i<10;++i){
			insertUserList.add(new TUser("BBB"+i));
		}
		userDao.batchInsert(insertUserList);
		
		//只有一條記錄的查找
		List<TUser> userList = userDao.queryByCondition("user_name=?", "AAAA");
		
		//InsertOrUpdate
		userDao.insertOrUpdate(new TUser("AAAA"), "user_name"); //update where user_name='AAAA'
		userDao.insertOrUpdate(new TUser("CCCC"), "user_name"); //insert CCCC

實現結果符合了設計目標,用起來仍是很方便的.this

四、實現類和接口說明:


如下內容應結合代碼看.[com.darcy.dao]包內,完整的代碼請點擊這裏獲取。 spa

(1)總覽: .net

.DaoFactory: 提供了集中獲取數據操做對象工廠,並緩存該對象.

.DBUtils: 封裝了Android API提供的數據庫實現

.IBaseDao: 面向用戶的接口

.GenericDao: IBaseDao的實現類

.GenericDao.DBTransction: 封裝了對事務的操做.

.QueryResult: 對查詢結果一行記錄的封裝類.封裝後的類能夠盡最大努力取到你想要的值,如數據庫中存儲1.0爲text類型,則經過QueryResult.getIntProperty()能夠得到正確的整型值1

.SqlHelper: 拼接SQL語句AND兩個對等對象之間直交換的輔助類

.Table: 表和對象的映射註解類

(2)接口設計:
 

public interface IBaseDao<T> {
	
	/**
	 * 建立表
	 */
	void createTable();

	/**
	 * 插入一條記錄
	 * 
	 * @param model
	 * @return
	 */
	boolean insert(T model);

	/**
	 * 插入多條記錄
	 * 
	 * @param model
	 * @return
	 */
	boolean batchInsert(List<T> dataList);

	/**
	 * 更新記錄
	 * 
	 * @param model
	 * @param whereClause
	 * @param whereArgs
	 * @return
	 */
	boolean update(T model, String whereClause, String... whereArgs);

	/**
	 * 決定是否insert或者Update
	 * @param model
	 * @param bindColumnNames 綁定的列名 ,默認是主鍵
	 * @return
	 */
	boolean insertOrUpdate(T model,String... bindColumnNames);
	
	/**
	 * 刪除記錄
	 * 
	 * @param whereClause
	 * @param whereArgs
	 * @return
	 */
	boolean delete(String whereClause, String... whereArgs);


	/**
	 * 刪除所有記錄
	 * @return
	 */
	boolean deleteAll();
	
	/**
	 * 根據條件查詢
	 * 
	 * @param whereClause
	 * @param whereArgs
	 * @return
	 */
	List<T> queryByCondition(String selection, String... selectionArgs);

	/**
	 *  根據條件查詢
	 * @param columns
	 * @param selection
	 * @param orderBy
	 * @param selectionArgs
	 * @return
	 */
	List<T> queryByCondition(String[] columns, String selection,
			String orderBy, String... selectionArgs);

	/**
	 * 根據條件查詢
	 * @param columns
	 * @param selection
	 * @param groupBy
	 * @param having
	 * @param orderBy
	 * @param selectionArgs
	 * @return
	 */
	List<T> queryByCondition(String[] columns, String selection,
			String groupBy, String having, String orderBy,
			String... selectionArgs);
	
	/**
	 * 只有惟一一條記錄的查詢
	 * 
	 * @return 若是沒有則返回null
	 */
	T queryUniqueRecord(String selection,String... selectionArgs);
	
	/**
	 * 自定義查詢
	 * @param sql
	 * @param bindArgs
	 * @return
	 */
	List<QueryResult> execQuerySQL(String sql, String... bindArgs);
	
	
	/**
	 * 執行Insert/Update/Delete等其餘非查詢SQL
	 * @param sql
	 * @param bindArgs
	 * @return
	 */
	boolean execUpdateSQL(String sql, Object... bindArgs);
}

爲何這麼多queryByCondition? 最小接口原則,這樣在用的時候提供更多選擇,代碼可變得更加精簡一些.

爲何提供execQuerySQL: 爲了支持一些複雜的查詢,如鏈接表查詢, 不然可能就要在代碼中寫不少此查詢才能作到.

同理execUpdateSQL:

不合理的地方:實際上這裏能夠查詢任何表,破壞了封裝性。

(3)接口實現(GenericDao):

createTable: 關鍵方法在SqlHelper.getCreateTableSQL中,這裏經過Java反射機制對採集傳進來的Class信息,而後拼接成建立表的SQL語句.

insert | update :關鍵方法:SqlHelper.parseModelToContentValues,其關鍵點也是在於利用Java反射機制來把model中的值轉化到ContentValue中.

queryByCondition: 也是同理.

insertOrUpdate(T model,String... bindColumnNames):這裏關鍵說一下insertOrUpdate的實現,建立表的時候咱們先保存好該表的主鍵,之後調用該方法時:若是model中的主鍵值已經存在,則update,反之則insert,以上是不帶參數的狀況,若是後面帶了列名,則根據列名進行聯合查詢該記錄是否存在決定insert Or update。

五、總結:

這個是今年在工做中其中的一點總結,在千方百計提供代碼的可重用性是便作了這個東西,可是,時間太趕,因此就本着夠用的原則先用着,代碼還有不少要完善的地方,但在該基礎上再進行構建一些新的支持應該就比較容易了。

相關文章
相關標籤/搜索