在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。
这个是今年在工做中其中的一点总结,在千方百计提供代码的可重用性是便作了这个东西,可是,时间太赶,因此就本着够用的原则先用着,代码还有不少要完善的地方,但在该基础上再进行构建一些新的支持应该就比较容易了。