使用GreenDao操作数据库

大神们都说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");

运行之后会出现:

User类

一对多

大家都知道在超市购物时候,一位顾客可以有很多订单,而一个订单只能属于一位顾客,所以这就成了一对多的关系,假设顾客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()表示得到该顾客所有订单:

Customer类

事实上它也是封装好了查询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博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容

  • 最近想学习一下使用GreenDao进行数据库操作,但是在网上查到的教程都是比较久的,而且在Android Stud...
    moshanghuakai88阅读 1,200评论 2 2
  • greenDAO greenDAO 是一个将对象映射到 SQLite 数据库中的轻量且快速的 ORM 解决方案。它...
    蕉下孤客阅读 16,091评论 18 104
  • greenDAO官方主页:http://greendao-orm.com/ 官方主页新地址:http://gree...
    sunny_zhang阅读 10,126评论 12 49
  • GreenDao 介绍:greenDAO是一个对象关系映射(ORM)的框架,能够提供一个接口通过操作对象的方式去操...
    小董666阅读 730评论 0 1
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,603评论 18 399