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