简介
greenDao是一个将对象映射到SQLite数据库中的轻量且快速的ORM解决方案。
参考
- 官网 http://greenrobot.org/greendao/
- Github https://github.com/greenrobot/greenDAO
配置greenDao
//根目录下的build.gradle下配置
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.1' //<-- add greenDao plugin
}
}
//app目录下的build.gradle配置
apply plugin: 'com.neenbedankt.android-apt'
greendao {
schemaVersion 1 //指定版本号,数据库升级的时候用
//可选属性
//daoPackage 'xxxx' 生成的DAOs,daomaster,和daosession包名。 默认为源实体的包名
//targetGenDir 'xxxx' 生成源应保存在该位置。 默认为构建目录里面生成的源文件夹( build/generated/source/greendao )。
//generatetests true 设置为true 自动生成单元测试。
//targetGenDirTests 'xxxx' 指定单元测试存储目录。默认为 src/androidTest/java。
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'org.greenrobot:greendao:3.2.0' //<-- greenDao
}
实体和注解
@Entity
public class Student {
@Id
private long stuId;
@Property(nameInDb = "NAME")
private String stuName;
@NotNull
private int age;
@Transient
private String desc;
}
Build - > Make Project 后会自动生成get/set方法并在build/generated/source/greendao/项目entity包名目录下生成相关Dao类
- 实体注解
schema:告知GreenDao当前实体属于哪个schema
active:标记一个实体处于活动状态,活动实体有更新、删除和刷新方法
nameInDb:在数据中使用的别名,默认使用的是实体的类名
indexes:定义索引,可以跨越多个列
createInDb:标记创建数据库表
- 基础属性注解
@Id :主键 Long型,可以通过@Id(autoincrement = true)设置自增长
@Property:设置保存到数据库中的列名,默认是的使用字段名
@NotNul:设置数据库表当前列非空
@Transient :添加次标记该属性不会插入到数据库
- 索引注解
@Index:使用@Index作为一个属性来创建一个索引,通过name设置索引别名,也可以通过unique给索引添加约束
@Unique:向数据库列添加了一个唯一的约束
- 关系注解
@ToOne:定义与另一个实体(一个实体对象)的关系
@ToMany:定义与多个实体对象的关系
@generated 由greendao产生的构造函数或方法(官方不建议修改此处的代码)
使用
在程序Application中配置
public class App extends Application {
private static DaoSession daoSession;
@Override
public void onCreate() {
super.onCreate();
//配置数据库
setupDatabase();
//配置可加密的数据库
//setupPwdDatabase();
}
/**
* 配置数据库
*/
private void setupDatabase() {
//创建数据库study.db"
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "study.db", null);
//获取可写数据库
SQLiteDatabase db = helper.getWritableDatabase();
//获取数据库对象
DaoMaster daoMaster = new DaoMaster(db);
//获取Dao对象管理者
daoSession = daoMaster.newSession();
}
/**
* 配置可加密的数据库(pwd为字符串密码)
*/
private void setupPwdDatabase(){
//创建数据库study.db"
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "study.db", null);
//获取数据库对象
DaoMaster daoMaster = new DaoMaster(helper.getEncryptedWritableDb("pwd"));
//获取Dao对象管理者
daoSession = daoMaster.newSession();
}
public static DaoSession getDaoInstant() {
return daoSession;
}
}
获取StudentDao对象
StudentDao studentDao=App.getDaoInstant().getStudentDao();
简单的增删改查实现
增
Student stu = new Student(1, "小明", 10);
studentDao.insert(stu);
studentDao.insertOrReplace(stu); //替换插入,当id相同情况下replace否则为insert
删
studentDao.deleteByKey(key);
studentDao.deleteAll();//批量删除
改
Student stu = new Student(1, "小明", 11);
studentDao.update(stu);
查
List stuList = studentDao.loadAll(); //批量查询
Student stu = studentDao.load(key); //根据id查询
//条件查询(id>1并且stuName like "小",根据age降序)
List stuList = studentDao.queryBuilder().where(StudentDao.Properties.StuId.gt(1), StudentDao.Properties.StuName.like("小"))
.orderDesc(StudentDao.Properties.Age).list();
数据库升级
首先在module的gradle文件中修改版本号
greendao {
schemaVersion 2 //之前是1
// daoPackage 'greendao'
// targetGenDir 'src/main/java'
}
如果只做了上边的操作,默认的会清除数据库的所有表,然后再重建数据库,查看DaoMaster.DevOpenHelper源码如下
/** WARNING: Drops all table on Upgrade! Use only during development. */
public static class DevOpenHelper extends OpenHelper {
public DevOpenHelper(Context context, String name) {
super(context, name);
}
public DevOpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
dropAllTables(db, true); // 这里会删除所有表
onCreate(db); //重建数据库
}
}
对于上线的项目,必须要做数据迁移,借用stackoverflow里大神的工具类:
public class MigrationHelper{
private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";
private static MigrationHelper instance;
public static MigrationHelper getInstance() {
if(instance == null) {
instance = new MigrationHelper();
}
return instance;
}
public void migrate(Database db, Class extends AbstractDao, ?>>... daoClasses) {
generateTempTables(db, daoClasses);
DaoMaster.dropAllTables(db, true);
DaoMaster.createAllTables(db, false);
restoreData(db, daoClasses);
}
private void generateTempTables(Database db, Class extends AbstractDao, ?>>... daoClasses) {
for(int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String divider = "";
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList properties = new ArrayList<>();
StringBuilder createTableStringBuilder = new StringBuilder();
createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");
for(int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if(getColumns(db, tableName).contains(columnName)) {
properties.add(columnName);
String type = null;
try {
type = getTypeByClass(daoConfig.properties[j].type);
} catch (Exception exception) {
exception.printStackTrace();
//Crashlytics.logException(exception);
}
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());
}
}
private void restoreData(Database db, Class extends AbstractDao, ?>>... daoClasses) {
for(int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList properties = new ArrayList<>();
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
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()));
//Crashlytics.logException(exception);
throw exception;
}
private static List getColumns(Database db,String tableName) {
List columns = new ArrayList<>();
Cursor cursor = null;
try {
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();
}
return columns;
}
}
用法
新建类继承DaoMaster.DevOpenHelper
,重写onUpgrade方法判断版本变化
public class MyOpenHelper extends DaoMaster.DevOpenHelper {
public MyOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
switch (newVersion){
case 1:break;
case 2:
//新版本,执行数据迁移
MigrationHelper.getInstance().migrate(db, StudentDao.class, TeacherDao.class);
break;
}
}
}
然后替换Application中初始化的DaoMaster.DevOpenHelper
为MyOpenHelper
/**
* 配置数据库
*/
private void setupDatabase() {
//创建数据库study.db"
MyOpenHelper helper = new MyOpenHelper(this, "study.db", null);
//获取可写数据库
SQLiteDatabase db = helper.getWritableDatabase();
//获取数据库对象
DaoMaster daoMaster = new DaoMaster(db);
//获取Dao对象管理者
daoSession = daoMaster.newSession();
}
over~
此文只是简单的greenDao的配置和使用,详细使用及文档,请移步 官网