greenDAO用法总结
greendao’的主要设计目标
- 性能最大最快的ORM(Android)
- 易于使用的API
- 高度优化的安卓系统
- 最小的内存消耗
- 小型图书馆规模,关注要点



package de.greenrobot.daogenerator.gentest;import de.greenrobot.daogenerator.DaoGenerator;import de.greenrobot.daogenerator.Entity;import de.greenrobot.daogenerator.Property;import de.greenrobot.daogenerator.Schema;import de.greenrobot.daogenerator.ToMany;/*** @description:使用说明:0.android工程导入dist/greendao-xxx.jar1.用实体生成demo,生成相应的实体及其数据库操作类2.(可选)对上述数据库操作类进行service层的封装3.修改DaoMaster中数据库名称及debug等参数4.最好单例化DaoMaster,并在application中进行初始化5.(在通过service中)创建DaoSession,获取相应dao进行实体的数据库相关操作6.参考链接(异或百度)官网http://greendao-orm.com/源码https://github.com/greenrobot/greenDAO更新说明2014-10-31DaoCore android工程源码DaoExample android工程demoDaoExampleGenerator 实体生成demoDaoGenerator 实体生成器源码* @author samy* @date 2015-4-27 下午5:28:22*/public class ExampleDaoGenerator {// (1)创建Java工程// (2)导入greenDao-generator.jar和freemarker.jar两个包。// freemarker是一个用java写的模板引擎,它能够基于模板来生成文本输出。应该就是用来自动生成DAO文件的。/*** @description:(3)创建schema* @author samy* @date 2015年6月15日 下午4:29:11*/public static void main(String[] args) throws Exception {// 创建schema时需要制定数据库的版本号、默认的Java package等参数。Schema schema = new Schema(1001, "com.zsy.sample.support.db.onepiececategory");// 默认Java package用来存放生成的entity、DAO文件、test代码。但也可以重新制定test文件的单独路径以及DAO文件的路径,代码:// schema.setDefaultJavaPackageTest("de.greenrobot.daoexample.test");// schema.setDefaultJavaPackageDao("de.greenrobot.daoexample.dao");// 另外,还有两个flag,用来标示entity是否是activie以及是否使用keep sections。代码:schema.enableKeepSectionsByDefault();// schema2.enableActiveEntitiesByDefault();// Keep sections:因为entity class在每次generator执行时均会覆盖原来的程序,为了能够添加用户自定义代码到entity中,需要设置该参数。只需要把自己的代码添加到下面的KEEP[]块中间就可以了。// KEEP INCLUDES - put your custom includes here// KEEP INCLUDES END// ...// KEEP FIELDS - put your custom fields here// KEEP FIELDS END// ...// KEEP METHODS - put your custom methods here// KEEP METHODS ENDaddProductCategory(schema);// addCustomerOrder(schema);/***(5)生成DAO文件 生成DAO文件就是使用main函数的最后一句话,其中后面的参数就是希望自动生成的代码对应的项目路径。* 注:设置的路径必须存在,否则会抛出异常。该路径是另外的工程下面的目录,当然也可以自己不这么做,只要这个目录存在就行。在schema创建的时候指定的package接口也是相对于该路径的。*/new DaoGenerator().generateAll(schema, "../DaoExample/src-gen");}private static void addProductCategory(Schema schema) {Entity note = schema.addEntity("OnePieceCategory");note.addIdProperty();note.addStringProperty("typeId");note.addStringProperty("typeName");note.addStringProperty("typeImage");note.addIntProperty("levelNum");note.addIntProperty("orderBy");note.addStringProperty("parentId");note.addStringProperty("webTypeImage");}private static void addNote(Schema schema) {Entity note = schema.addEntity("OncePieceCategory");note.addIdProperty();note.addStringProperty("typeId");note.addStringProperty("typeName");note.addStringProperty("parentId");}/*** @description:(4)创建entity* schema中可以添加entity,简单的理解应该是entity对应一个具体的java class,entity可以添加property。Entity通常也是对应一个table。* 除了添加property之外,entity也可以添加to-one和to-many关系,即添加一对一的关系和一对多的关系。* @author samy* @date 2015年6月15日 下午4:28:51*/private static void addCustomerOrder(Schema schema) {Entity customer = schema.addEntity("Customer");customer.addIdProperty();customer.addStringProperty("name").notNull();Entity order = schema.addEntity("Order");order.setTableName("ORDERS"); // "ORDER" is a reserved keywordorder.addIdProperty();Property orderDate = order.addDateProperty("date").getProperty();Property customerId = order.addLongProperty("customerId").notNull().getProperty();order.addToOne(customer, customerId);ToMany customerToOrders = customer.addToMany(order, customerId);customerToOrders.setName("orders");customerToOrders.orderAsc(orderDate);}}
查询:
(1)QueryBuilder
使用过sql语句查询的人都会有一种感触(主要针对不是专职开发数据库并对sql不是很熟练的人),写起来复杂、不能再第一时间发现问题(只能在运行过程中验证sql的正确性)、查找bug麻烦等等。QueryBuilder的出现就是为了解决sql使用的问题,提高开发效率。
看一个略微复杂的例子,查询first name是Joe,并在1970年10月以及之后的所有人:
QueryBuilder qb = userDao.queryBuilder();
qb.where(Properties.FirstName.eq("Joe"),
qb.or(Properties.YearOfBirth.gt(1970),
qb.and(Properties.YearOfBirth.eq(1970), Properties.MonthOfBirth.ge(10))));
List youngJoes = qb.list();
(2)Lazylist
greenDAO支持返回唯一查询结果(如果没有返回null) ---- 调用Query或QueryBuilder的unique()方法;
也支持返回list ---- 调用list()方法。
当不希望返回null作为结果时,则调用uniqueOrThrow()方法,当结果null时将直接抛出异常。
返回多个结果解释:
list(): 所有entity均会被加载到内存中。结果仅是一个简单的ArrayList。使用最简单。
listLazy(): 查询结果会根据需要加载到内存中。列表中的元素仅在accessed for the first time,它才会被加载并缓存。该方法必须主动关闭(Must be closed)。
listLazyUncached(): 虚拟的结果列表,任何对元素的方法实际都会到数据库中去加载数据。Must be closed
listIterator(): 根据需要迭代结果(lazily)。数据不缓存。Must be closed
在greenDAO实现中,后3中其实都使用的LazyList类。为了实现根据需要加载,其内部实现上是保存了数据库cursor的引用。这也是为何这3中方式must be closed,其就是为了释放内部cursor和迭代器(通常是在try-finally块中完成close)。
(3)Query
解释:Query类代表了一个可以被重复执行的查询。在QueryBuilder内部其实也是会定义一个Query并执行完成查询。
这将带来极大地方便,因为任何人都不希望在每次查询的时候总是写一遍query代码。同时Query还可以根据需要改变参数。如下实例代码:
使用Query对象查询名为Joe并出生在1970年的人:
Query query = userDao.queryBuilder().where(
Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970))
.build();
List joesOf1970 = query.list();
然后想再查询出生在1977年之后并叫Marias的人:
query.setParameter(0, "Maria");
query.setParameter(1, 1977);
List mariasOf1977 = query.list();
注意:参数的编号是创建query所设置的顺序。
(4)多线程查询
有时我们希望在多线程中执行查询。从greenDAO 1.3版本开始,实例化Query对象均会绑定到其自己的线程,这样我们就可以安全的设置Query参数,因为其他线程无法影响到。如果其他线程使用别的线程的query(比如设置参数、执行查询)将会抛出异常。因此,我们也不需要做同步工作,而且不要加锁,因为加入相关的事务用到了该Query对象将导致死锁。
为完全地避免可能产生的死锁,1.3版本引入了forCurrentThread()方法。该方法将返回本线程内的Query实例,每次调用该方法时,参数均会被重置为最初创建时的一样。
(5)原生sql查询
推荐的方法执行原生sql语句是通过QueryBuilder和WhereCondition.StringCondition。如下代码:
Query query = userDao.queryBuilder().where(
new StringCondition("_ID IN " + "(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)").build();
假如QueryBuilder没有提供你需要的特性,你也可以使用queryRaw() 和 queryRawCreate() 方法。具体就不再详细介绍了。
(6)删除操作(delete query)
删除操作会删除所有满足条件的实体。为实现批量删除(bulk delete),调用QueryBuilder的 buildDelete方法并执行DeleteQuery。该部分API还不稳定,可能会改变就不介绍了。
(7)问题定位(日志)
你可能会遇到查询结果并不是预期的那样,这时候你就可以设置两个静态flag参数来打日志定位问题:
QueryBuilder. LOG_SQL = true ;QueryBuilder. LOG_VALUES = true ;
这将会将产生的sql命令以及传递的参数以日志方式输出,由此方便程序员定位问题。
使用:(增删改查操作)
1.查询
范例1:查询某个表是否包含某个id:
public boolean isSaved(int ID)
{QueryBuilder<SaveList> qb = saveListDao.queryBuilder();qb.where(Properties.Id.eq(ID));qb.buildCount().count();return qb.buildCount().count() > 0 ? true : false;}范例2:获取整个表的数据集合,一句代码就搞定!
public List<PhotoGalleryDB> getPhotoGallery()
{
return photoGalleryDao.loadAll();// 获取图片相册
}范例3:通过一个字段值查找对应的另一个字段值(为简便直接使用下面方法,也许有更简单的方法,尚未尝试)
/** 通过图片id查找其目录id */
publicintgetTypeId(intpicId){QueryBuilder<PhotoGalleryDB> qb = photoGalleryDao.queryBuilder();qb.where(Properties.Id.eq(picId));if{return}else{return}}范例4:查找所有第一姓名是“Joe”并且以lastname排序。
List joes = userDao.queryBuilder()
where(Properties.FirstName.eq("Joe"))orderAsc(Properties.LastName)list();范例5:多重条件查询
(1)获取id为cityId并且infotype为HBContant.CITYINFO_SL的数据集合:
publicList<CityInfoDB> getSupportingList(intcityId){QueryBuilder<CityInfoDB> qb = cityInfoDao.queryBuilder();qb.where(qb.and(Properties.CityId.eq(cityId),Properties.InfoType.eq(HBContant.CITYINFO_SL)));qb.orderAsc(Properties.Id);return}(2)获取firstname为“Joe”并且出生于1970年10月以后的所有user集合:
QueryBuilder qb = userDao.queryBuilder();qb.where(Properties.FirstName.eq("Joe"),qb.or(Properties.YearOfBirth.gt(1970),qb.and(Properties.YearOfBirth.eq(1970), Properties.MonthOfBirth.ge(10))));List youngJoes = qb.list();范例6:获取某列对象
picJsonDao.loadByRowId(picId);2.增添/插入、修改
插入数据更加简单,也是只要一句代码便能搞定!
publicvoidaddToPhotoTable(Photo p){photoDao.insert(p);}插入时需要new一个新的对象,范例如下:
DevOpenHelper helper =newDaoMaster.DevOpenHelper(this,"notes-db",null);db = helper.getWritableDatabase();daoMaster = new DaoMaster(db);daoSession = daoMaster.newSession();noteDao = daoSession.getNoteDao();Note note = new Note(null, noteText, comment, new Date())noteDao.insert(note);修改更新:
photoDao.insertOrReplace(photo);photoDao.insertInTx(photo);categoryDaoSession.runInTx(new Runnable() { @Override public void run() {OnePieceCategoryDao.dropTable(db, true);OnePieceCategoryDao.createTable(db, true);for (OnePieceCategory category : list) {categoryDao.insert(category);count++;}}}3.删除:
(1)清空表格数据
/** 清空相册图片列表的数据 */publicvoidclearPhoto(){photoDao.deleteAll();}(2)删除某个对象
publicvoiddeleteCityInfo(intcityId){QueryBuilder<DBCityInfo> qb = cityInfoDao.queryBuilder();DeleteQuery<DBCityInfo> bd = qb.where(Properties.CityId.eq(cityId)).buildDelete();bd.executeDeleteWithoutDetachingEntities();}参考:https://github.com/greenrobot/greenDAO/issues/34
由上可见,使用greenDAO进行数据库的增删改查时及其方便,而且性能极佳。
private static DaoMaster daoMaster;private static DaoSession daoSession;/*** 取得DaoMaster** @param context* @return*/public static DaoMaster getDaoMaster(Context context){if (daoMaster == null){OpenHelper helper = new DaoMaster.DevOpenHelper(context, HBContant.DATABASE_NAME, null);daoMaster = new DaoMaster(helper.getWritableDatabase());}return daoMaster;}/*** 取得DaoSession** @param context* @return*/public static DaoSession getDaoSession(Context context){if (daoSession == null){if (daoMaster == null){daoMaster = getDaoMaster(context);}daoSession = daoMaster.newSession();}return daoSession;}
public class DBHelper{private static Context mContext;private static DBHelper instance;private CityInfoDBDao cityInfoDao;private DBHelper(){}public static DBHelper getInstance(Context context){if (instance == null){instance = new DBHelper();if (mContext == null){mContext = context;}// 数据库对象DaoSession daoSession = HBApplication.getDaoSession(mContext);instance.cityInfoDao = daoSession.getCityInfoDBDao();}return instance;}/** 添加数据 */public void addToCityInfoTable(CityInfo item){cityInfoDao.insert(item);}/** 查询 */public List<EstateLoveListJson> getCityInfoList(){QueryBuilder<CityInfo> qb = cityInfoDao.queryBuilder();return qb.list();}/** 查询 */public List<CityInfo> getCityInfo(){return cityInfoDao.loadAll();// 查找图片相册}/** 查询 */public boolean isSaved(int Id){QueryBuilder<CityInfo> qb = cityInfoDao.queryBuilder();qb.where(Properties.Id.eq(Id));qb.buildCount().count();return qb.buildCount().count() > 0 ? true : false;// 查找收藏表}/** 删除 */public void deleteCityInfoList(int Id){QueryBuilder<CityInfo> qb = cityInfoDao.queryBuilder();DeleteQuery<CityInfo> bd = qb.where(Properties.Id.eq(Id)).buildDelete();bd.executeDeleteWithoutDetachingEntities();}/** 删除 */public void clearCityInfo(){cityInfoDao.deleteAll();}/** 通过城市id查找其类型id */public int getTypeId(int cityId){QueryBuilder<CityInfo> qb = cityInfoDao.queryBuilder();qb.where(Properties.Id.eq(cityId));if (qb.list().size() > 0){return qb.list().get(0).getTypeId();}else{return 0;}}/** 多重查询 */public List<CityInfo> getIphRegionList(int cityId){QueryBuilder<CityInfoDB> qb = cityInfoDao.queryBuilder();qb.where(qb.and(Properties.CityId.eq(cityId), Properties.InfoType.eq(HBContant.CITYINFO_IR)));qb.orderAsc(Properties.Id);// 排序依据return qb.list();}}
greenDao混淆
对greenDao混淆要写一下代码
-libraryjars libs/greendao-1.3.7.jar
-keep class de.greenrobot.dao.** {*;}
#保持greenDao的方法不被混淆
-keepclassmembers class * extends de.greenrobot.dao.AbstractDao {
#用来保持生成的表名不被混淆 public static java.lang.String TABLENAME; } -keep class **$Properties