弄明白greenDao之前我们应该先了解什么是ORM(Object Relation Mapping 即 对象关系映射),说白了就是将面向对象编程语言里的对象与数据库关联起来的一种技术,而greenDao就是实现这种技术之一,所以说greenDao其实就是一种将java object 与SQLite Database关联起来的桥梁,它们之间的关系 如下图所示;
greenDao可以说是当今最流行,最高效而且还在迭代的关系型数据库。而且greenDao3.0还支持RxJava操作,greenDao如此受欢迎离不开以下几点:
1.module的build.gradle添加:
apply plugin: 'org.greenrobot.greendao'//添加
2.module的build.gradle依赖添加:
compile'org.greenrobot:greendao:3.1.1'
compile'org.greenrobot:greendao-api:3.1.1'
3.module的build.gradle根级别下配置:
greendao {
schemaVersion 1 //数据库版本号
//设置DaoMaster 、DaoSession、Dao包名
daoPackage 'com.greendao.dao' //生成的dao路径 targetGenDir 'src/main/java-gen' //数据库文件的目录}
sourceSets { main { java.srcDirs = ['src/main/java', 'src/main/java-gen'] } }
4.在project的在build.gradle中配置:
dependencies {
classpath 'com.android.tools.build:gradle:2.2.2'
classpath 'org.greenrobot:greendao-gradle-plugin:3.1.0'//greenDao生产代码插件
}
核心类介绍
DaoMaster:
DaoSession:
5.编写java实体类,注意注解:
@Entity
//如果该实体属于多个表单,可以使用该参数;
schema = "myschema",
// 该实体属于激活状态,激活状态的实体有更新,删除,刷新方法;
active = true,
// 给这个表指定一个名字,默认情况下是名字是类名
nameInDb = "AWESOME_USERS",
// 可以给多个属性定义索引和其他属性.
indexes = { @Index(value = "name DESC", unique = true) },
//是否使用GreenDao创建该表.
createInDb = false,
// 是否所有的属性构造器都应该被生成,无参构造器总是被要求
generateConstructors = true,
// 如果该类中没有set get方法是否自动生成
generateGettersSetters = true
基本注释属性
@ID 一般会选择long/Long属性作为Entity ID(即数据库中的主键)autoincrement=true表示主键会自增如果false就会使用旧值
@Property 可以自定义一个该属性在数据库中的名称,默认情况下数据库中该属性名称是Bean对象中的 属性名但是不是以驼峰式而是以大写与下划线组合形式来命名的比如:customName将命名为 CUSTOM_NAME;注意:外键不能使用该属性;
@NotNull 确保属性值不会为null值;
@Transient 使用该注释的属性不会被存入数据库中;
@Unique
将属性变成唯一约束属性;也就是说在数据库中该值必须唯一
@Generated
提示开发者该属性不能被修改;并且实体类的方法,属性,构造器一旦被@Generated注释就不能被再次修改,否则或报错
Error:Execution failed for task ':app:greendao'.> Constructor (see
ExampleEntity:21) has been changed after generation.Please either mark
it with @Keep annotation instead of @Generated to keep it untouched,or
use @Generated (without hash) to allow to replace it.
这是因为在通过javabean对象自动生成entities类时,greenDao会增加实体类代码,@Generated注释部分与GreenDao增加的代码相关,胡乱修改@Generated代码,就会导致entities部分属性与javabean不匹配导致报错;有俩种方法可以避免这种错误
还原@Generated 改动的部分,当然你也可以完全删除@Generated 注释的部分下一次 app build时将会自动生成;
使用@Keep 代替@Generated 这将告诉greenDao 不会使用该属性注释的代码,但是这种改变可能会破坏entities类和greenDAO的其他部分的连接;注意:默认情况下 greenDao会使用合理的默认值去设置实体类,因此开发者不需要为每个属性都添加注释
@Entity(nameInDb="C_CFG_TEST")
public class Test { @Id
private Long id;//主键id,必须Long型
@ Property(nameInDb="TYPE") //设置Table栏位名称
private String type;//类型
}
@Id
private Long id;
@Index(unique = true)
private String key;
@Entity
public class User {
@Id
private Long id;
@Index(unique = true)
private String name;
}
编写完Java Object之后Make一下Project ,Android Studio会自动产生文件:
com.greendao.dao
- TestDao.java
6.在Application中完成Database Initialized:
public class MyApplication extends Application {
public static DaoSession daoSession = null; public static MyApplication instance; public static Context context; public static SQLiteDatabase db = null; public static DaoMaster.DevOpenHelper helper = null; public static DaoMaster daoMaster = null; private String TAG = MyApplication.class.getSimpleName(); public static Context getContext() { return context; } public synchronized static MyApplication getInstance() { if (null == instance) { instance = new MyApplication(); } return instance; }
public static DaoSession getDaoSession() { return daoSession; } /** *
* 下面代码仅仅需要执行一次,一般会放在application
* initial Database */ private void setupDatabase() { // 通过 DaoMaster 的内部类 DevOpenHelper,你可以得到一个便利的 SQLiteOpenHelper 对象。 // 可能你已经注意到了,你并不需要去编写「CREATE TABLE」这样的 SQL 语句,因为 greenDAO 已经帮你做了。 // 注意:默认的 DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。 // 所以,在正式的项目中,你还应该做一层封装,来实现数据库的安全升级。 helper = getHelperInstance(this); db = helper.getWritableDatabase(); // 注意:该数据库连接属于 DaoMaster,所以多个 Session 指的是相同的数据库连接。 if (daoMaster == null) { daoMaster = new DaoMaster(db); } if (daoSession == null) { daoSession = daoMaster.newSession(); } } /** * @param context * @return */ public synchronized DaoMaster.DevOpenHelper getHelperInstance(Context context) { if (helper == null) { helper = new DaoMaster.DevOpenHelper(context, "greendaodb", null); } return helper; } ; @Override public void onCreate() { super.onCreate(); /** * Setup Greendao Database */ setupDatabase(); //获取全局Context context = getApplicationContext(); } public SQLiteDatabase getDb() { if (db == null) { setupDatabase(); } return db; }}
7.实例化mAdvertDao后,用其操作实体bean对象,例如:
TestDao.insert(T entity);//增
TestDao.delete(T entity);//删,也可deleteByKey(K key)
TestDao.update(T entity);//改
TestDao.load(K key);//查
注:save()方法比较特殊既能进行插入操作也能执行修改操作
Query:
Ex1:
List users = userDao.queryBuilder()
.where(Properties.Name.eq("UserName"))
.orderAsc(Properties.Name) .list();
Ex2:
QueryBuilder qb = userDao.queryBuilder();
qb.where(Properties.FirstName.eq("Joe"),//第一个约束条件姓乔
qb.or(Properties.YearOfBirth.gt(1970),//或者出生日期大于1970年
qb.and(Properties.YearOfBirth.eq(1970),
Properties.MonthOfBirth.ge(10))//并且在1970年出生 但是月份大于
10月的));
List youngJoes = qb.list();
分页查询
注:qb.list() - 执行多次查询应使用Query类,Query(or QueryBuilder)中的unique()方法 - 只想获取一个结果。
查询与LazyList类
Query : Query类表示一个查询能够执行很多次;而当通过QueryBuilder的任何查询方法(eg:list())来获取查询结果时,querybuilder都会 在其内部创建Query来执行查询语句的;如果执行多次查询应该使用Query对象; 如果只想获取一个结果时可以使用Query(or QueryBuilder)中的unique()方法;
LazyList : 可以通过以下方法获取查询结果集合;
list() 缓存查询结果;list()类型一般为ArrayList
listLazy() 懒查询,只有当调用list()中的实体对象时才会执行查询操作并且只缓存第一次被查询的结果,需要关闭
listlazyUncached() 懒查询,只有当调用list()中的实体对象时才会执行查询操作并且不缓存;
listIterator() 对查询结果进行遍历,不缓存,需要关闭;后面三个类是LazyList中的方法,LazyList为了执行不同的缓存策略其内部持有数据库的cursor对象;
一般情况下这三个方法执行完毕后会自动关闭cursor;但是防止在还没有执行完查询结果时,对象被终结cursor还是无法被关闭的情况发生,需要手动关闭close();
// fetch users with Joe as a first name born in 1970Query
query = userDao.queryBuilder().where(
Properties.FirstName.eq("Joe"),
Properties.YearOfBirth.eq(1970)).build();List joesOf1970 =
query.list(); // using the same Query object, we can change the
parameters// to search for Marias born in 1977
later:query.setParameter(0, "Maria");query.setParameter(1,
1977);List mariasOf1977 = query.list();
使用SQL查询
如果QueryBuilder不能满足需求可以使用以下俩种方法来实现你的需求;
Query query = userDao.queryBuilder().where( new
StringCondition("_ID IN " + "(SELECT USER_ID FROM
USER_MESSAGE WHERE READ_FLAG = 0)")).build();
Query query = userDao.queryRawCreate( ", GROUP G WHERE
G.NAME=? AND T.GROUP_ID=G._ID", "admin");
Insert:
Function ft1 = new Function();
ft1.setFUNCTION("test"+count);
ft1.setUSER_ID("test"+count);
ft1.setQTY(10);
fd.insertOrReplace(ft1);
/**
* 原生的sqlite
*/
// String insertSql = String.format("insert into %s (%s,%s,%s)
// values('%s','%s','%s')",
// NoteDao.TABLENAME,
// NoteDao.Properties.Title.columnName,
// NoteDao.Properties.Content.columnName,
// NoteDao.Properties.CreateTime.columnName,
// note.getTitle(),
// note.getContent(),
// note.getCreateTime());
/**
* 4:批量插入
*/
// public void insertBatch(List notes){
// daoSession.getNoteDao().insertInTx(notes);
// }
Delete:
/**
* Greendao function
*/
// fd.delete(entity);
// fd.deleteAll();
// fd.deleteByKey(key);
/**
* 原生的sqlite
*/
String deleteSql = String.format("delete from %s where %s='test2'", fd.TABLENAME,
FunctionDao.Properties.USER_ID.columnName);
// ds.getDatabase().rawQuery(sql, null);
Logger.d(deleteSql);
ds.getDatabase().execSQL(deleteSql);