大神们都说GreenDao性能最好,使用方便,最近在做一个项目,刚好用到操作本地数据库,so机缘巧合,开始学习GreenDao,顺便做一下笔记。
(1)原理
我总有那么一个习惯,就是使用别人的工具,总想着能对其原理了解一二,一来可以学习点经验,二来就是能更好的使用这个工具。原理不在本章讨论范围内,故贴上一个网址,供大家好好参详:ORM对象关系映射之GreenDAO源码解析
(2)eclipse配置使用
GreenDao不像其他工具一样,直接将jar包导进去就可以用了。它需要我们新建一个java工程,导入greenDao-generator.jar和freemarker.jar两个包,生成我们所需要的类文件和相应的Dao文件,然后copy到我们的Android工程供我们使用。具体请参照:Android 配置使用 GreenDao 教程
(3)高级使用(copy,以免链接失效)
增加:
dao.insert(Student entity);//添加一个
dao.insertInTx(Student...entity);//批量添加
删除:
dao.deleteByKey(Long key);//根据主键删除
dao.deleteByKeyInTx(Long...keys);//批量删除
dao.delete(Student entity);//根据实体删除
dao.deleteInTx(Student... entities);//
批量删除dao.deleteAll();//全部删除
修改:
dao.update(Student entity);//根据实体更新
dao.updateInTx(Student...entities);//批量更新
查找:
Query query = dao.queryBuilder().where(StudentDao.Properties.Name.eq(content)).build();
List list = query.list();//或者利用sql语言查询
Query query = dao.queryBuilder().where( new StringCondition("_ID IN "+"(SELECT _ID FROM STUDENT WHERE AGE = 20)").build()
创建属性约束
我们可以在为Schema添加实体的时候,在实体添加属性时候进行属性的一些约束,如
Schema schema = new Schema(1,"com.sunzxyong.greendao");
Entity entity = schema.addEntity("Student");
entity.addIdProperty().autoincrement().primaryKey();//主键,自增
entity.addStringProperty("name").notNull();//不为空
entity.addIntProperty("age");
entity.addBooleanProperty("is_man").notNull();
new DaoGenerator().generateAll(schema,"../GreenDAODemo/app/src/main/java-gen");
保持实体中自定义的代码不会被覆盖
假如你需要在实体类中自定义一些字段变量和方法,而再次generator的实体类通常会覆盖以前的,如果你不想覆盖掉你自定义的代码,可以这样设置:
schema.enableKeepSectionsByDefault();//通过次Schema对象添加的所有实体都不会覆盖自定义的代码//或者
entity.setHasKeepSections(true);//单独让某个实体不覆盖自定义的代码
如果设置了上述代码,则生成的实体中会多出以下代码:
// 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 END
多线程环境下使用GreenDAO
在多线程的环境下使用查询,你必须调用query的 forCurrentThread()为当前的线程获得一个query实例,如:
Query query = dao.queryBuilder().where(StudentDao.Properties.Name.eq(content)).build().forCurrentThread();
List list = query.list();
LazyList和List
在通过queryBuilder建立查询时候:
1、如果你想得到一个唯一的结果,可以调用Query的unique()方法,如:
Query query = dao.queryBuilder().where(StudentDao.Properties.Name.eq(content)).build().forCurrentThread();
Student student = query.unique();
2、如果你想得到多个结果,可以调用Query的list()或者listLazy()方法,这两个方法有什么区别呢?
(1)List - 当所有的实体查询完会立即一次性加载到内存中,即在List集合中
(2)LazyList - 懒加载的方式,即实体按照需求加载进入内存(查询完不会立即加载到内存中,只有在需要数据的时候也就是遍历这个LazyList的时候,才会加载到内存中),列表中的元素在第一次访问时候就会同时缓存在一个ArrayList集合中,它再次访问这些元素则直接从集合中拿。如果你不想缓存这些数据又想懒加载,可以通过Query的listLazyUncached()方法。这个集合在使用完毕必须close,即调用:listLazy.close();
GreenDao的代码混淆配置
-keepclassmembersclass*extendsde.greenrobot.dao.AbstractDao {
publicstaticjava.lang.String TABLENAME;
}
-keepclass**$Properties
借助两个Flag打印出SQL命令和传入的值
通过设置这两个Flag,可以在控制台中打印出我们执行的sql语句以及传入的值,方便用于检查
//下面两个Flag的设置可以在控制台中打印出此次查询的sql语句和value值
QueryBuilder.LOG_SQL = true;
QueryBuilder.LOG_VALUES = true;
Query query = dao.queryBuilder().where(StudentDao.Properties.Name.eq(content)).build().forCurrentThread();
LazyList list = query.listLazyUncached();
(4)建立多表关联(copy,以免链接失效)
一对一关联
通常我们在操作数据库的时候,我们往往不是单独的对一张表进行操作,而是对这张表的操作会联动的影响另外一张表或者多张表,比如:现在有两张表,一张是用户User表(有name、age、sex三个字段),一张是头像Picture表(有pictureId、pictureName、width、height四个字段)。假如用户表和头像表是一对一关系,一个用户只有一个头像,一个头像只能有一个用户,所以要建立这两张表之间的联系,这两张表肯定是需要关联的,这样就可以通过用户的信息得到它的头像信息。我们知道在数据库中,关联两张表(暂且不说多对多关系的)一般都是把一张表的主键作为另外一张表的外键来做的,所以在Android中也同样,如果我们要关联User表和Picture表,那么只需要把Picture表的主键(假如是pictureId)作为User表的外键即可,另外一个亦是如此,如:
�
假设还是以上面的场景为例,则利用GreenDAO建立User表和Picture表一对一的关联可以这样建立:
//把User表的主键name作为Picture表的外键,把Picture的主键pictureId作为User表的外键,这样得到任何一个实体的信息都可以得到关联的另外一个实体的信息
Property property = user.addLongProperty("pictureId").getProperty();
user.addToOne(picture,property);
Property propertyName = picture.addStringProperty("name").getProperty();
picture.addToOne(user,propertyName);
在为Schema添加实体的时候,我们在相应的实体中添加另外一个表的主键即可:
Schema schema = new Schema(1,"com.sunzxyong.greendao2");//User
Entity user = schema.addEntity("User");
user.addStringProperty("name").notNull().primaryKey();
user.addStringProperty("sex");//Picture
Entity picture = schema.addEntity("Picture");
picture.addLongProperty("pictureId").primaryKey();
picture.addStringProperty("pictureName").notNull();
picture.addIntProperty("width");picture.addIntProperty("height");
//建立一对一关联
Property property = user.addLongProperty("pictureId").getProperty();
user.addToOne(picture,property);//user通过pictureId可以找到对应的picture
property propertyName = picture.addStringProperty("name").getProperty();
picture.addToOne(user,propertyName);//picture通过name可以找到对应的user
new DaoGenerator().generateAll(schema,"../GreenDAODemo/app/src/main/java-gen");
运行之后会出现:
一对多
大家都知道在超市购物时候,一位顾客可以有很多订单,而一个订单只能属于一位顾客,所以这就成了一对多的关系,假设顾客Customer表有customerId(primaryKey)、name两个属性,订单Order表有orderId(primaryKey)、money两个属性。
Schema schema = new Schema(1,"com.sunzxyong.greendao3");//顾客
Entity customer = schema.addEntity("Customer");
customer.addLongProperty("customerId").primaryKey();
customer.addStringProperty("name").notNull();//订单
Entity order = schema.addEntity("Order");
order.addLongProperty("orderId").primaryKey();
order.addDoubleProperty("money").notNull();
//建立一对多关联(顾客对订单为一对多)
Property property = order.addLongProperty("customerId").getProperty();
order.addToOne(customer,property);//order通过customerId可以找到对应的customer
customer.addToMany(order,property).setName("orders");//customer可以通过orders找到很多order
new DaoGenerator().generateAll(schema,"../GreenDAODemo/app/src/main/java-gen");
当设置了顾客对订单一对多关联后,Order实体(和表)中会多一个属性为customerId,所以通过订单我们可以得到该顾客信息,而Customer实体(和表)中会多一个List集合变量:List orders,表示该顾客的所有订单,其中orders其实是我们自定义的名字,在刚刚setName("orders")就是给这个变量设置了“orders“名称,而Customer实体中还提供了一个方法getOrders()表示得到该顾客所有订单:
事实上它也是封装好了查询Order中顾客id为customerId的所有订单。
多对多
通常来说,在建立多对多关联上,我们都会采用新建一张中间表,利用中间表把多对多这种复杂关系简单化,在通常的选课系统上,一个学生可以选择多门课,一门课可以被多个学生选,这就是多对多关系了,假设Student有studentId、name两个属性,Course有courseId、courseName两个属性,则建立多对多关系为:
Schema schema = new Schema(1,"com.sunzxyong.greendao4");//学生
Entity student = schema.addEntity("Student");
student.addLongProperty("studentId").primaryKey();
student.addStringProperty("name").notNull();//课程
Entity course = schema.addEntity("Course");
course.addLongProperty("courseId").primaryKey();
course.addStringProperty("courseName").notNull();
//建立多对多关联
Entity studentCourse = schema.addEntity("StudentCourse");
Property studentId = studentCourse.addLongProperty("studentId").getProperty();
Property courseId = studentCourse.addLongProperty("courseId").getProperty();
studentCourse.addToOne(student,studentId);
studentCourse.addToOne(course,courseId);
student.addToMany(studentCourse, studentId);
course.addToMany(studentCourse,courseId);
new DaoGenerator().generateAll(schema,"../GreenDAODemo/app/src/main/java-gen");
这样就建立学生和课程表多对多的关联,学生实体和课程实体中都有这么一个方法:
public List getStudentCourseList(){
//...}
意思就是得到一个StudentCourse的集合,而StudentCourse实体中又有这么两个方法:
public Student getStudent(){//...}
public Course getCourse(){//...}
所以当我们得到了StudentCourse的List集合,我们可以通过StudentCourse中的这两个方法来得到对应的学生或者课程信息。
(5)自定义属性转换器PropertyConverter(copy,以免链接失效)
在使用GreenDAO定义实体的属性时候,通常来说定义的实体属性名就是对应的表的字段名、实体中属性的类型(如Long、String等)就是表的字段名类型,但是我们难免会有不一样的需求,比如实体中我定义了一个Color类型的属性或者其它自定义类型的属性,而表的字段类型只有一些原始类型肯定是没有这些类型的,所以这时候该怎么办呢?
不用急,GreenDAO给我们提供了一个强大的工具,就是属性转换器:PropertyConverter。这是一个接口,我们使用它可以让实体的属性类型不再局限于原始类型, 可以自定义任何的类型,充分保证了实体的灵活性。既然实体的类型可以是自定义的任何类型,而表中只有一些原始类型,那么自定义类型和原始类型之间怎么进行值的交互呢?这是通过PropertyConverter来进行转换的,它就是相当于一个中间层,让数据在实体中是一种表现形式,而在表中又是另外一种表现形式。所以在进行CRUD的时候我们就可以直接赋值了,转换工作交给PropertyConverter做就好了。
好了,我们来使用一下吧,刚刚说PropertyConverter是个接口,那么要定义一个属性转换器肯定是需要实现这个接口的,实现这个接口是要在Android工程中,而这个接口中有两个方法需要实现,为:
public class MyPropertyConverter implements PropertyConverter {
@Override
public String convertToEntityProperty(Long databaseValue) {
returnnull;
}
@Override
public Long convertToDatabaseValue(String entityProperty) {
returnnull;
}
}
其中PropertyConverter接口中需要定义两个泛型,意思分别为P:实体中自定义的类型,D:数据库中的类型。
下面通过一个简单的实例来看看具体怎么使用:
假如有一个时间数据,实体类中的类型为String类型(用来直接展示2015-09-16 17:50 星期三格式的数据),而数据库中的类型为Long类型,用来存放精确的毫秒值,而且需要进行一系列的运算,所以类型肯定是要为Long类型。
我们先来定义一个属性转换器:
public class MyPropertyConverter implements PropertyConverter {
@Override
public String convertToEntityProperty(Long databaseValue) {
SimpleDateFormat format =newSimpleDateFormat("yyyy-MM-dd HH:mm EEEE", Locale.CHINA);
String result = format.format(newDate(databaseValue));returnresult;
}
@Override
public Long convertToDatabaseValue(String entityProperty) {
SimpleDateFormat format =newSimpleDateFormat("yyyy-MM-dd HH:mm EEEE", Locale.CHINA);
Long result;
try{
Datedate= format.parse(entityProperty);
result =date.getTime();
}catch(ParseException e) {
result =0L;
}
returnresult;
}
}
然后在添加实体的时候这样添加:
Schema schema = new Schema(1,"com.sunzxyong.greendao5");
Entity item = schema.addEntity("Item");
item.addLongProperty("time").customType("java.lang.String","com.sunzxyong.greendaodemo.MyPropertyConverter");
new DaoGenerator().generateAll(schema,"../GreenDAODemo/app/src/main/java-gen");
其中customType()方法的第一个参数为实体中的自定义类型的包名+类名,第二个参数为转换器的包名+类名。
点击运行生成实体后,我们打开Item类看看,发现time的类型为String类型:
public classItem {
private String time;
public Item() {
}
public Item(String time) {
this.time = time;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
我们再打开数据库文件看看time字段的类型:
发现为Integer类型,原因是我用第三方工具打开后,设计表中的类型没有Long类型,而就为Integer类型了
所以利用自定义属性转换器PropertyConverter我们只需要直接按实体中的类型添加数据,存入表中时候转换器会帮我们做好一系列转换工作。
以上都是别人写的,因为条理比较清晰,自己整理整理,做项目的时候可以迅速查阅一下。
参照:Sunzxyong CSDN博客