greendao3.0重复插入

史上最高效的ORM方案——GreenDao3.0高级用法 - 简书
史上最高效的ORM方案——GreenDao3.0高级用法
session 缓存
自定义参数类型
与数据库操作相关的AS插件
session 缓存
如果你有多个相同的查询语句去执行,猜猜看返回给你的对象是一个还是多个?比如说像下面这样
QueryBuilder&Project& projectQueryBuilder = projectDao
.queryBuilder()
.where(ProjectDao.Properties.UserName.eq("123456"));
Query&Project& query = projectQueryBuilder.build();
Project project1=query.unique();
QueryBuilder&Project& projectQueryBuilder1 = projectDao
.queryBuilder()
.where(ProjectDao.Properties.UserName.eq("123456"));
Query&Project& query2 = projectQueryBuilder1.build();
Project project2=query.unique();
答案是project1==project2而且project2查询出来的速度要比project1查询出来的速度快很多倍;
这是因为在同一个session中如果一个entities已经被session记录那么下一次再次操作该实体时,greenDao会先从内存中查找,如果内存中没有再去数据库中查找。这样一方面就极大的提高greenDao的查询效率,另一方面也是需要特别注意的是当entities更新过 greenDao仍然会从内存中取出旧值,所以如果entities更新过,需要去调用daoseesion.clear()方法清除缓存后才能查到最新值,否则查询到的将还是保存在内存中的值。
下面介绍下清除缓存有两种方法
清除所所有的缓存
daoSession.clear();
清除指定Dao类的缓存
projectDao = daoSession.getNoteDao();projectDao.detachAll();
1. 1:1关联
当我们在使用sqlite数据库来实现表的1:1关联时,通常我们会在主表中定义一个外键去关联副表,当要查询对应的数据时,首先我们要知道查询数据的外键,然后需要用外键去副表中查询所需要的数据。比如下面这样
public class Customer {
public class Order {
private long customerId;
Customer表通过id与Order表关联,查询Order的Customer时需要先知道Order中的customerId然后根据id=customerId值再去数据库中查询该id所对应的Customer对象。然而在greenDao中一个注释就可以搞定,只需要使用@ToOne注释来定义一个关联对象即可。
@ToOne 定义了一个entities与另一个entities的1:1对应关系。通过joinProperty参数来定义一个外键下面是代码示例
public class Order {
private long customerId;
@ToOne(joinProperty = "customerId")
public class Customer {
这样只要获得Order对象就能通过getCustomer()方法获取Order所对应的Customer了,这样是不是很高效,很简便。其实getCustomer方法也很简单,就是在底层帮助我们封装好了查询语句而已,另外getCustomer获取的对象也是懒查询机制,只有真正使用getCustomer方法查询到的对象时greenDao才会执行查询操作。如果你想立即执行查询操作可以调用DAO类的loadDeep()与queryDeep()方法。
2. 1:N 关联
在1对1关联中每个顾客只能与一个订单对应,但是现实生活中肯定不只是这样,也会出现一个顾客下多个订单的情况。如果出现这种需求的话,按照原生Sqlite的思路一样是通过外键关联即可,只是这一次查询的对象会有很多个,但是使用greenDao的1:1关联方式显然不行。不过别担心greenDao还给我们准备了@ToMany注释。
**@ToMany **定义了一个entities(这个标记为源实体)与另一个entities(这个标记为目标实体)的多个对象的关联关系:@Tomany有一下三种方式来定义1:N的映射关系。
referencedJoinProperty 在目标实体中我们需要定义一个与源实体关联起来的外键,即Order中的customerId,然后需要在源实体里我们需要将customerId作为referencedJoinProperty的属性。说起来很拗口,其实代码很简单;
public class Customer {
@Id private L
@ToMany(referencedJoinProperty = "customerId")
@OrderBy("date ASC")
private List&Order&
public class Order {
@Id private L
private long customerId;
是不是很简单通过referencedJoinProperty来标注下俩个实体之间的外键即可
joinProperties这个参数是referencedJoinProperty 参数的升级版。在referencedJoinProperty参数中我们发现俩个实体关联的外键是CustomerId与id,但是如果我们的需求是外键不能通过id来定义,需要用自己自定义属性来定义,第一种方法就没法用了,而joinProperties就是为了解决这个需求的。
public class Customer {
@Id private L
@Unique private S
@ToMany(joinProperties = {
@JoinProperty(name = "tag", referencedName = "customerTag")
@OrderBy("date ASC")
private List&Site&
public class Order {
@Id private L
@NotNull private String customerT
其实如果把
@ToMany(joinProperties = {
@JoinProperty(name = "id", referencedName = "customerId")
这样的话就和第一种方法实现原理是一样的了。
@JoinEntity 定义了N:M的映射关系。
public class Product {
@Id private L
@JoinEntity(
entity = JoinProductsWithOrders.class,
sourceProperty = "productId",
targetProperty = "orderId"
private List&Order& ordersWithThisP
public class JoinProductsWithOrders {
@Id private L
private Long productId;
private Long orderId;
public class Order {
@Id private L
3. 关联表的更新与解析
关联的查询也是懒加载机制,而且查询的结果会保存在缓存中下一次查询的时候如果缓存有会直接从缓存中获取结果。
同样关联表更新时因为有缓存机制的存在你需要将改动的表手动的通过add()方法来更新关联表中的对象或者直接清除缓存。
// 获取当前顾客的订单列表
List&Order& orders1 = customer.getOrders();
// 插入一个新订单
Order order = new Order();
order.setCustomerId(customer.getId());
daoSession.insert(order);
// 再一次获取顾客的订单
List&Order& orders2 = customer.getOrders();
// 因为缓存列表没有更新所以订单1与订单2的大小相等
assert(orders1.size() == orders2.size);
// 也是相同的对象
assert(orders1.equals(orders2));
//调用该方法后,才能更新缓存列表
orders1.add(newOrder);
//删除时也许要手动将缓存列表里面的数据删除
List orders = customer.getOrders();
// 从数据库中移除
daoSession.delete(someOrder);
// 手动从缓存列表移除
orders.remove(someOrder);
//如果数据库更新后不想手动添加数据可以使用resetXX()方法来清除缓存
customer.resetOrders();
List orders = customer.getOrders();
有些时候我们的表没有使用ToOne与ToMany建立关联关系,但是我们又想一步到位。这时我们可以使用greenDao的多表查询功能来帮助我们减少不必要的代码。
1. 关联单个表
//查询地址是住在迪拜大楼的用户
QueryBuilder&User& queryBuilder = userDao.queryBuilder();
queryBuilder.join(Address.class, AddressDao.Properties.userId)
.where(AddressDao.Properties.Street.eq("迪拜大楼"));
List&User& users = queryBuilder.list();
通过queryBuilder.join()方法即可完成,其用法也很简单第一个参数是关联的类,第二个是关联类中的关联属性。
2.关联多个表
//查询在欧洲人口超过100000的城市
QueryBuilder qb = cityDao.queryBuilder().where(Properties.Population.ge(1000000));
Join country = qb.join(Properties.CountryId, Country.class);
Join continent = qb.join(country, CountryDao.Properties.ContinentId,
Continent.class, ContinentDao.Properties.Id);
continent.where(ContinentDao.Properties.Name.eq("Europe"));
List&City& bigEuropeanCities = qb.list();
通过queryBuilder.join()链式调用来实现多表查询
注意:多表查询的前提是我们已经定义好了外键来关联表与表之间的关系。
自定义参数类型
1.默认类型参数 :greenDao默认支持的类型参数如下
boolean, Boolean
int, Integer
short, Short
long, Long
float, Float
double, Double
byte, Byte
2.自定义类型参数: 如果greenDao的默认参数类型满足不了你的需求,比如你想定义一个颜色属性,那么你可以使用数据库支持的原生数据类型通过PropertyConverter类转换成你想要的颜色属性。
首先你需要给自定义类型参数添加 @Convert注释并添加对应参数
converter:参数转换类,columnType:在数据库中对应的类型
实现PropertyConverter类
下面是用通过使用数据库支持的Integer类型来转换成数据库不支持的枚举类型
public class User {
@Convert(converter = RoleConverter.class, columnType = Integer.class)
public enum Role {
DEFAULT(0), AUTHOR(1), ADMIN(2);
Role(int id) {
public static class RoleConverter implements PropertyConverter&Role, Integer& {
//将Integer值转换成Role值
public Role convertToEntityProperty(Integer databaseValue) {
if (databaseValue == null) {
for (Role role : Role.values()) {
if (role.id == databaseValue) {
return Role.DEFAULT;
//将Role值转换成Integer值
public Integer convertToDatabaseValue(Role entityProperty) {
return entityProperty == null ? null : entityProperty.
与数据库相关的AS插件
快速清除数据库本地数据--ADB IDEA
调试工具同时可以快速查看数据表结构和数据--Stetho
感兴趣的同学可以搜索下这俩个插件真的很好用。
上期有同学有同学提问greenDao的多线程同步机制,在这里我简单解释下:
greenDao多线程同步可以通过forCurrentThread()来实现的,具体原理很简单我们看下源码就知道了
//获取当前线程id
long threadId = Thread.currentThread().getId();
synchronized (queriesForThreads) {
//queryRef是一个Map集合
WeakReference&Q& queryRef = queriesForThreads.get(threadId);
Q query = queryRef != null ? queryRef.get() :
if (query == null) {
query = createQuery();
//保存query
queriesForThreads.put(threadId, new WeakReference&Q&(query));
System.arraycopy(initialValues, 0, query.parameters, 0, initialValues.length);
这是源码的核心部分,从上面我们可以看出greenDao是通过将线程id与query对象存储在Map集合中建立1:N的映射关系,不同线程只会取出属于自己的query而不会调用其他线程的query。
1. 什么是greenDao 弄明白greenDao之前我们应该先了解什么是ORM(Object Relation Mapping 即 对象关系映射),说白了就是将面向对象编程语言里的对象与数据库关联起来的一种技术,而greenDao就是实现这种技术之一,所以说greenD...
大家好,在上一篇文章中,我主要介绍了GreenDao3.0的最基本的用法,当然也是最常用的用法,如果你的项目里没有特别复杂的多表关联需求的话,我相信那篇文章的知识点已经足够使用了。但是,如果你是一个求知欲特别强的人或者手上有要在本地创建复杂的数据库需求的话,我相信认真读完本...
Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线)。分布式系统的协调导致了样板模式, 使用Spring Cloud开发人员可以快速地支持实现这些模式的服务和应用程序。他们将在任何分布式...
1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语法,集合的语法,io的语法,虚拟机方面的语法。 1、一个&.java&源文件中是否可以包括多个类(不是内部类)?有什么限制? 可以有多个类,但只能有一个publ...
本文包括:1、Hibernate 的查询方式2、HQL (Hibernate Query Language) 查询3、HQL 的投影查询4、HQL 的聚合函数查询5、QBC (Query By Criteria ) 条件查询6、QBC 离线条件查询7、SQL查询方式(了解)...
感悟:善于观察生活,善于挖掘获取新的资源,订下属于自己的标签。善于运用获取的资源,如果是自己不擅长的,那就寻找擅长的人来帮忙,利用资源做到极致。或者利用它赚去人生第一桶金,再去寻找自己感兴趣的领域专攻,从客户的利益出发更容易获得成功。
1、 我是在凌晨三点,上厕所的时候,看到了我的分身,很不凑巧,她那个时候,恰好站在厕所里。 “喂,您能不能先出去,阿姐我要上厕所。”刚进厕所的时候,我还处于半睡半醒的状态,分不清这是梦还是现实,也不知道厕所里的白色身影是人还是鬼。如果想到她是鬼这一方面,换做平常,我是会拼命...
笔触划过纸页 思念也横过眉梢 我独守一隅的思念 等你黎明的归来 时间像是蜗牛的爬行 又好似迟迟不肯散去的夜色 此刻,我只想让时间过得快一些
「遇见」 小凡的青春期是从高一那年开始的,脸上的青春痘冒个不停。按她后来的话说就是,青春迟钝的像只乌龟。 时光淌淌流过,转眼间到了高三。 有天下课的时候大东来她们班找班长,大东叫住了小凡:“同学嘿嘿,可以帮我找下你们的班长吗?”说完大东挠了挠头,嘴角轻轻上扬了30度。 小凡...GreenDao 3.0使用 - 简书
GreenDao 3.0使用
GreenDao 3.0采用注解的方式来定义实体类,通过gradle插件生成相应的代码。
一,在as中导入相关的包
compile 'org.greenrobot:greendao:3.0.1'
compile 'org.greenrobot:greendao-generator:3.0.0'
二,在build.gradle中进行配置:
apply plugin: 'org.greenrobot.greendao'
buildscript {
repositories {
mavenCentral()
dependencies {
classpath 'org.greenrobot:greendao-gradle-plugin:3.0.0'
在gradle的根模块中加入上述代码后,sync project的时候,gradle会自动去maven仓库下载一个gradle的插件,当然了,这个插件就是为greenDAO服务的,用来生成数据库相关的代码。
简单的介绍下通过gradle插件生成数据库代码的步骤:每次在make project之前,它会扫描项目中所有的@Entity文件(greenDAO中数据库的实体类),根据实体类生成DaoSession、DaoMaster以及所有实体类的dao类,生成的文件默认目录为:build/generated/source/greendao,若不想修改生成的路径,可以将此路径设置为资源目录。
三,我们也可以自定义这个路径,下面就来介绍如何在gradle中配置greenDAO的相关属性:
greendao {
schemaVersion 1
daoPackage 'com.example.yyf.mvpdemo.greendao.gen'
targetGenDir 'src/main/java'
在gradle的根模块中加入上述代码,就完成了我们的基本配置了。
schemaVersion----&指定数据库schema版本号,迁移等操作会用到
daoPackage--------&通过gradle插件生成的数据库相关文件的包名,默认为你的entity所在的包名
targetGenDir--------&这就是我们上面说到的自定义生成数据库文件的目录了,可以将生成的文件放到我们的java目录中,而不是build中,这样就不用额外的设置资源目录了
四,编写实体类
public class User {
@Transient
private int tempUsageC // not persisted
编写完成之后点击as中Build菜单栏中的Make Project,make完成之后会发现我们的User类中突然多了好多代码,这就是greenDAO自动为你生成的了,代码如下:
public class User {
@Transient
private int tempUsageC // not persisted
public String getName() {
return this.
public void setName(String name) {
this.name =
public Long getId() {
return this.
public void setId(Long id) {
@Generated(hash = )
public User(Long id, String name) {
this.name =
@Generated(hash = )
public User() {
buiild之后生成了get 和 set方法,以及在目录文件下生成了三个文件,
QQ图片51.png
五,增删改查操作
首先要初始化数据库
DaoMaster.DevOpenHelper openHelper = new DaoMaster.DevOpenHelper(MyApplication.getContext(), "notes-db", null);
SQLiteDatabase db = openHelper.getWritableDatabase();
DaoMaster mDaoMaster = new DaoMaster(db);
mDaoSession = mDaoMaster.newSession();
User user = new User(id, name);
userDao.insert(user);
如果id为null,则自动为其分配自增的id
List&User& userList = userDao.queryBuilder()
.where(UserDao.Properties.Id.notEq(999))
.orderAsc(UserDao.Properties.Id)
.build().list();
先通过queryBuilder生成查找构造器,然后写相应条件进行查询,where 条件判断
orderAsc 排序
limit 查询条数
list() 查询结果为一个集合
User findUser = GreenDaoManager.getInstance().getSession().getUserDao().queryBuilder()
.where(UserDao.Properties.Name.eq(prevName)).build().unique();
if(findUser != null) {
findUser.setName(newName);
GreenDaoManager.getInstance().getSession().getUserDao().update(findUser);
Toast.makeText(MyApplication.getContext(), "修改成功", Toast.LENGTH_SHORT).show();
Toast.makeText(MyApplication.getContext(), "用户不存在", Toast.LENGTH_SHORT).show();
修改要先查询出此内容,然后再根据相应的条件去修改,unique()表示查询一条。
User findUser = userDao.queryBuilder().where(UserDao.Properties.Name.eq(name)).build().unique();
if(findUser != null){
userDao.deleteByKey(findUser.getId());
先查出数据,然后根据条件去删除。
六,执行sql语句
String sql ="insert into user values (null,'111')";
GreenDaoManager.getInstance().getSession().getDatabase().execSQL(sql);
七,greendao中的注解
@Entity 定义实体
@nameInDb 在数据库中的名字,如不写则为实体中类名
@indexes 索引
@createInDb 是否创建表,默认为true,false时不创建
@schema 指定架构名称为实体
@active 无论是更新生成都刷新
(三) @NotNull 不为null
(四) @Unique 唯一约束
(五) @ToMany 一对多
(六) @OrderBy 排序
(七) @ToOne 一对一
(八) @Transient 不存储在数据库中
(九) @generated 由greendao产生的构造函数或方法
(一)GreenDao简介 GreenDao是一个对象关系映射(ORM)的开源框架,目前最主流的安卓数据库操作框架。 首先说说什么是对象关系映射ORM:Object Relational Mapping,是一种将对象层次结构映射成关系型结构的方法。 通过上面的简单分析,来说...
用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? ... Android 获取 View 宽高的常用正确方式,避免为零 - 掘金 相信有很多...
GreenDao介绍 greenDAO是一个对象关系映射(ORM)的框架,能够提供一个接口通过操作对象的方式去操作关系型数据库,它能够让你操作数据库时更简单、更方便。如下图所示: GreenDao 优点: 库文件比较小,小于100K,编译时间低,而且可以避免65K方法限制 ...
用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金Cover 有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? ... Android 获取 View 宽高的常用正确方式,避免为零 - 掘金相信有很多朋友...
Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线)。分布式系统的协调导致了样板模式, 使用Spring Cloud开发人员可以快速地支持实现这些模式的服务和应用程序。他们将在任何分布式...
不可否认,爱情有时候的确会让人变得盲目。当我们身陷在一段感情中时,我们会觉得特别迷茫,会不知所措,会心生嫉妒,当然也会夹杂着些许甜蜜与快乐。爱情如同阳光雨露,滋润着我们干涸的心灵。爱情最美妙的地方在于你永远不知道下一秒会发生什么。 阿芬是一个很要强的女生。她在工作与生活中,...
详见实例讲解iOS应用的设计模式开发中的Visitor访问者模式 摘录如下:访问者模式(Visitor),表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 访问者模式使用场景 访问者模式的目的是要把处理从数据结构分离...
项目介绍简历
我可能永远不会理解乔布斯的 Stay hungry, stay foolish. 但我应该已经明白了 The journey is the rewarding. 就像我知道自己腰间仅存的赘肉终将消失,腹肌正在养成,刻意逢迎的日子也将不再!我始终都在坚持。 考研人都引以为傲的...
春风十里送晨阳,百花亭外衫满泪。 一夜秋霜愁满雪,半生残月望乡楼。greendao3.0以上使用步骤(二):数据库到底该怎么升级
这一篇看看数据库到底该怎么升级呢?看我升级后的效果
没有升级前的页面显示
没有升级前的数据库
升级后的页面显示
升级后的数据库
看增加了一个NUM字段 。
最新有小伙伴遇到数据库升级问题了,说网上都是2.0版本的升级方法,自己使用的是3.0,没法升级数据库了….
然后问别人,别人让他改为2.0版本,让数据库里面有两个表供应用操作,天啦这还了得,我用的也是3.0,那以后还得了,非把人累死……..
数据库的升级大家都知道,创建临时表,进行过渡储存而已,网上有人提供了一个MigrationHelper类,真好正好可以使用!
蹦出了这样一个大bug,请看:
什么新增字段不能为空?
我没有设置呀,到底为什么呢?
我相信有的小伙伴也遇到过吧!那下面我们一起来看看怎么回事吧
创建临时表--&删除原表--&创建新表--&复制临时表数据到新表并删除临时表;这样数据库表的更新就完成了
首先我们引入MigrationHelper类,内容如下:
package cn.hnshangyu.testgreendao.
import android.database.C
import android.text.TextU
import android.util.L
import org.greenrobot.greendao.AbstractD
import org.greenrobot.greendao.database.D
import org.greenrobot.greendao.internal.DaoC
import java.util.ArrayL
import java.util.A
import java.util.L
import cn.hnshangyu.testgreendao.greendao.DaoM
public class MigrationHelper {
private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";
private static MigrationH
public static MigrationHelper getInstance() {
if (instance == null) {
instance = new MigrationHelper();
public void migrate(Database db, Class&? extends AbstractDao&?, ?&&... daoClasses) {
generateTempTables(db, daoClasses);
DaoMaster.dropAllTables(db, true);
DaoMaster.createAllTables(db, false);
restoreData(db, daoClasses);
* 生成临时列表
* daoClasses
private void generateTempTables(Database db, Class&? extends AbstractDao&?, ?&&... daoClasses) {
for (int i = 0; i & daoClasses. i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String divider = "";
String tableName = daoConfig.
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList&String& properties = new ArrayList&&();
StringBuilder createTableStringBuilder = new StringBuilder();
createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");
for (int j = 0; j & daoConfig.properties. j++) {
String columnName = daoConfig.properties[j].columnN
if (getColumns(db, tableName).contains(columnName)) {
properties.add(columnName);
String type = null;
type = getTypeByClass(daoConfig.properties[j].type);
} catch (Exception exception) {
exception.printStackTrace();
createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);
if (daoConfig.properties[j].primaryKey) {
createTableStringBuilder.append(" PRIMARY KEY");
divider = ",";
createTableStringBuilder.append(");");
db.execSQL(createTableStringBuilder.toString());
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(" FROM ").append(tableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
* 存储新的数据库表 以及数据
* daoClasses
private void restoreData(Database db, Class&? extends AbstractDao&?, ?&&... daoClasses) {
for (int i = 0; i & daoClasses. i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String tableName = daoConfig.
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList&String& properties = new ArrayList();
for (int j = 0; j & daoConfig.properties. j++) {
String columnName = daoConfig.properties[j].columnN
if (getColumns(db, tempTableName).contains(columnName)) {
properties.add(columnName);
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
db.execSQL(insertTableStringBuilder.toString());
db.execSQL(dropTableStringBuilder.toString());
private String getTypeByClass(Class&?& type) throws Exception {
if (type.equals(String.class)) {
return "TEXT";
if (type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class)) {
return "INTEGER";
if (type.equals(Boolean.class)) {
return "BOOLEAN";
Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));
exception.printStackTrace();
private List&String& getColumns(Database db, String tableName) {
List&String& columns = new ArrayList&&();
Cursor cursor = null;
cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
if (cursor != null) {
columns = new ArrayList&&(Arrays.asList(cursor.getColumnNames()));
} catch (Exception e) {
Log.v(tableName, e.getMessage(), e);
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
然后需要知道数据库更新表的方法是DaoMaster类中的onUpgrade方法:
这个类为配置greendao后系统自动生成,不能直接在这里操作,不然每次运行此类都是重新生成的。
构建MyOpenHelper帮助类,重写onUpgrade方法进行操作:
package cn.hnshangyu.testgreendao.
import android.content.C
import android.database.sqlite.SQLiteD
import android.util.L
import org.greenrobot.greendao.database.D
import cn.hnshangyu.testgreendao.greendao.DaoM
import cn.hnshangyu.testgreendao.greendao.StudentD
public class MyOpenHelper extends DaoMaster.OpenHelper {
public MyOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
* 数据库升级
* oldVersion
* newVersion
public void onUpgrade(Database db, int oldVersion, int newVersion) {
MigrationHelper.getInstance().migrate(db,StudentDao.class);
什么地方使用MyOpenHelper 类呢?
之前的greendao3.0以上使用步骤(一)中,我创建了一个DbManager管理类来进行对数据库的统一管理,今天同样使用这个类:
那么与之前的有什么区别呢??
其实就是在获取DaoMaster时有所改变,打开数据库方式不同
1、之前的方法
* 获取DaoMaster
public static DaoMaster getDaoMaster(Context context) {
if (null == mDaoMaster) {
synchronized (DbManager.class) {
if (null == mDaoMaster) {
mDaoMaster = new DaoMaster(getWritableDatabase(context));
return mDaoM
* 获取DaoMaster
* 判断是否存在数据库,如果没有则创建数据库
public static DaoMaster getDaoMaster(Context context) {
if (null == mDaoMaster) {
synchronized (DbManager.class) {
if (null == mDaoMaster) {
MyOpenHelper helper = new MyOpenHelper(context,DB_NAME,null);
mDaoMaster = new DaoMaster(helper.getWritableDatabase());
return mDaoM
3、整个类的类容:
package cn.hnshangyu.testgreendao.
import android.content.C
import android.database.sqlite.SQLiteD
import cn.hnshangyu.testgreendao.greendao.DaoM
import cn.hnshangyu.testgreendao.greendao.DaoS
import cn.hnshangyu.testgreendao.helper.MyOpenH
public class DbManager {
public static final boolean ENCRYPTED = true;
private static final String DB_NAME = "test.db";
private static DbManager mDbM
private static DaoMaster.DevOpenHelper mDevOpenH
private static DaoMaster mDaoM
private static DaoSession mDaoS
private Context mC
private DbManager(Context context) {
this.mContext =
mDevOpenHelper = new DaoMaster.DevOpenHelper(context, DB_NAME);
getDaoMaster(context);
getDaoSession(context);
public static DbManager getInstance(Context context) {
if (null == mDbManager) {
synchronized (DbManager.class) {
if (null == mDbManager) {
mDbManager = new DbManager(context);
return mDbM
* 获取可读数据库
public static SQLiteDatabase getReadableDatabase(Context context) {
if (null == mDevOpenHelper) {
getInstance(context);
return mDevOpenHelper.getReadableDatabase();
* 获取可写数据库
public static SQLiteDatabase getWritableDatabase(Context context) {
if (null == mDevOpenHelper) {
getInstance(context);
return mDevOpenHelper.getWritableDatabase();
* 获取DaoMaster
* 判断是否存在数据库,如果没有则创建数据库
public static DaoMaster getDaoMaster(Context context) {
if (null == mDaoMaster) {
synchronized (DbManager.class) {
if (null == mDaoMaster) {
MyOpenHelper helper = new MyOpenHelper(context,DB_NAME,null);
mDaoMaster = new DaoMaster(helper.getWritableDatabase());
return mDaoM
* 获取DaoMaster
* 获取DaoSession
public static DaoSession getDaoSession(Context context) {
if (null == mDaoSession) {
synchronized (DbManager.class) {
mDaoSession = getDaoMaster(context).newSession();
return mDaoS
现在我们在bean对象里面加一个num字段,注意类型:
package cn.hnshangyu.testgreendao.
import org.greenrobot.greendao.annotation.E
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.K
import org.greenrobot.greendao.annotation.G
import org.greenrobot.greendao.annotation.NotN
@Entity(generateConstructors = false)
public class Student {
private int
private int
public int getNum() {
public void setNum(int num) {
this.num =
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", num=" + num +
public Student() {
public Student(String name, int age) {
this.name =
this.age =
public Student(Long id, String name, int age) {
this.name =
this.age =
public Long getId() {
public void setId(Long id) {
public String getName() {
public void setName(String name) {
this.name =
public int getAge() {
public void setAge(int age) {
this.age =
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student)
return name.equals(student.name);
public int hashCode() {
return (int) (id ^ (id &&& 32));
大家看到了我加了一个int类型的字段
最后就是升级版本了,在build升级版本
版本升为2了,同步一下
然后运行程序………
哎呀!你会发现报了一个重大bug,就是开始我提到的新增字段不能为空,这是为什么呢?bean对象中我没有限定不能为空啊!
好吧我们看看怎么回事吧!
首先他报错的部位为MigrationHelper的restoreData方法,把新临时表数据拷贝到新表中
既然字段不能为空,大部分是因为创建表的时候造成的
MigrationHelper创建表的时候调用的是DaoMaster的createAllTables方法:
/** Creates underlying database table using DAOs. */
public static void createAllTables(Database db, boolean ifNotExists) {
StudentDao.createTable(db, ifNotExists);
从greendao生成的源码中可以看到调用的是StudentDao的createTable方法
那么在StudentDao中:
/** Creates the underlying database table. */
public static void createTable(Database db, boolean ifNotExists) {
String constraint = ifNotExists? "IF NOT EXISTS ": "";
db.execSQL("CREATE TABLE " + constraint + "\"STUDENT\" (" +
"\"_id\" INTEGER PRIMARY KEY ," +
"\"NAME\" TEXT," +
"\"AGE\" INTEGER NOT NULL ," +
"\"NUM\" INTEGER NOT NULL);");
哎呀!发现了,INTEGER NOT NULL
(integer)不能为空?这下知道原因了,int类型的是不能为空的怎么办呢??
我们又看到了NAME这个字段他是TEXT类型,也就是String类型的可以为空,
因此,我们先把NUM字段改为String类型
package cn.hnshangyu.testgreendao.
import org.greenrobot.greendao.annotation.E
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.K
import org.greenrobot.greendao.annotation.G
import org.greenrobot.greendao.annotation.NotN
@Entity(generateConstructors = false)
public class Student {
private int
public String getNum() {
public void setNum(String num) {
this.num =
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", num=" + num +
public Student() {
public Student(String name, int age) {
this.name =
this.age =
public Student(Long id, String name, int age) {
this.name =
this.age =
public Long getId() {
public void setId(Long id) {
public String getName() {
public void setName(String name) {
this.name =
public int getAge() {
public void setAge(int age) {
this.age =
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student)
return name.equals(student.name);
public int hashCode() {
return (int) (id ^ (id &&& 32));
重新进行上述数据库更新操作,把bean对象中的num改为了String类型,
运行后结果正常,数据库更新了!
看看StudentDao新创建表
/** Creates the underlying database table. */
public static void createTable(Database db, boolean ifNotExists) {
String constraint = ifNotExists? "IF NOT EXISTS ": "";
db.execSQL("CREATE TABLE " + constraint + "\"STUDENT\" (" +
"\"_id\" INTEGER PRIMARY KEY ," +
"\"NAME\" TEXT," +
"\"AGE\" INTEGER NOT NULL ," +
"\"NUM\" TEXT);");
新的字段NUM为TEXT类型,一切正常!
总结:在greendao3.0升级数据库时
我们基本思路为:
创建临时表--&删除原表--&创建新表--&复制临时表数据到新表并删除临时表
并且我们新增加的和修改的字段做好为String类型,避免字段不能为null的情况发生
到这里greendao3.0数据库更新说明完毕……
有什么不妥,欢迎指出,谢谢啦………
没有更多推荐了,}

我要回帖

更多关于 greendao 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信