文档章节

Android通用DAO(数据访问对象)设计和实现

叶大侠
 叶大侠
发布于 2014/01/15 20:50
字数 1188
阅读 7275
收藏 64

1、前言:


在Android的应用开发中,往往会涉及到许多数据的存储和交互,其中,内嵌的sqlite数据库会作为首选的方案,在一些涉及比较多的数据交互情境中,通常表现为表的数量比较多,我们就有必要开发一个比较通用的数据访问框架了。

2、设计目标:

(1):能够方便地创建表和对象的对应关系.[这里我们以注解的方式实现]

(2):能够以统一的方式方便的进行数据的增删查改.

也就是能够使用类似Hibernate等框架的使用: 如增加一条记录的使用习惯:

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

3、实现结果初体验:


(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

实现结果符合了设计目标,用起来还是很方便的.

4、实现类和接口说明:


以下内容应结合代码看.[com.darcy.dao]包内,完整的代码请点击这里获取。

(1)总览:

.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。

5、总结:

这个是今年在工作中其中的一点总结,在想方设法提供代码的可重用性是便做了这个东西,但是,时间太赶,所以就本着够用的原则先用着,代码还有很多要完善的地方,但在该基础上再进行构建一些新的支持应该就比较容易了。





   



© 著作权归作者所有

共有 人打赏支持
叶大侠

叶大侠

粉丝 59
博文 44
码字总数 67312
作品 5
广州
程序员
私信 提问
加载中

评论(3)

叶大侠
叶大侠

引用来自“幻影浪子”的评论

源码地址,放出来瞅瞅吧

在文章中啦..http://git.oschina.net/yeguozhong/AndroidGenericDao
幻影浪子
幻影浪子
源码地址,放出来瞅瞅吧
幻影浪子
幻影浪子
源码地址,放出来瞅瞅吧
移动开发之设计模式- 数据访问对象模式(IOS&Android)

资源 完全参照数据访问对象模式|菜鸟教程但不包括IOS代码 数据访问对象模式 数据访问对象模式(Data Access Object Pattern)或 DAO 模式用于把低级的数据访问 API 或操作从高级的业务服务中...

FlanneryZJ
2018/12/18
0
0
【翻译】安卓架构组件(6)-Room持久化类库

相关文章: 【翻译】安卓架构组件(1)-App架构指导 【翻译】安卓架构组件(2)-添加组件到你的项目中 【翻译】安卓架构组件(3)-处理生命周期 【翻译】安卓架构组件(4)-LiveData 【翻译】安卓架构...

Chuckiefan
2017/06/07
0
0
android数据库持久化框架

android数据库持久化框架 前言 Android中内置了SQLite,但是对于数据库操作这块,非常的麻烦.其实可以试用第3方的数据库持久化框架对之进行结构上调整, 摆脱了访问数据库操作的细节,不用再去写...

ZHL
2012/09/08
0
0
老生常谈Android的MVP架构

原生框架问题 由于原生 Android 开发应该已经是一个基础的 MVC 框架,所以在初始开发的时候并没有遇到太多框架上的问题,可是一旦项目规模到了一定的程度,就需要对整个项目的代码结构做一个...

LaxusJ
2018/04/23
0
0
学Android开发,入门语言java知识点

Android是一种以Linux为基础的开源码操作系统,主要使用于便携设备,而linux是用c语言和少量汇编语言写成的,如果你想研究Android,就去学java语言吧。 Android开发入门教程 -Java语言,最差...

抉择很难
2015/12/11
185
0

没有更多内容

加载失败,请刷新页面

加载更多

Windows 上安装 Scala

在安装 Scala 之前需要先安装 Java 环境,具体安装的详细方法就不在这里描述了。 您可以自行搜索我们网站中的内容获得其他网站的帮助来获得如何安装 Java 环境的方法。 接下来,我们可以从 ...

honeymose
今天
1
0
数据库篇多表操作

第1章 多表操作 实际开发中,一个项目通常需要很多张表才能完成。例如:一个商城项目就需要分类表(category)、商品表(products)、订单表(orders)等多张表。且这些表的数据之间存在一定的关系...

stars永恒
今天
3
0
nginx日志自动切割

1.日志配置(Nginx 日志) access.log----记录哪些用户,哪些页面以及用户浏览器,IP等访问信息;error.log------记录服务器错误的日志 #配置日志存储路径:location / {      a...

em_aaron
昨天
5
0
java 反射

基本概念 RTTI,即Run-Time Type Identification,运行时类型识别。RTTI能在运行时就能够自动识别每个编译时已知的类型。   要想理解反射的原理,首先要了解什么是类型信息。Java让我们在运...

细节探索者
昨天
2
0
推荐转载连接

https://www.cnblogs.com/ysocean/p/7409779.html#_label0

小橙子的曼曼
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部