Android 理论

GreenDao3.0简单使用2

2018-12-12  本文已影响0人  禄子_c79b
    https://blog.csdn.net/qq_35956194/article/details/79167897

一、在项目根目录中的build.gradle

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.0'  //添加greendao
    }
}

二、在app目录下的build.gradle配置

apply plugin: 'org.greenrobot.greendao'    //所有标签之外添加
//配置
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.greenrobot:greendao-gradle-plugin:3.0.0'
    }
}
//配置数据库
greendao {
    schemaVersion 1       //数据库版本号
//设置DaoMaster、DaoSession、Dao包名,也就是要放置这些类的包的全路径。(此路径下自动生成一些dao文件。)
    daoPackage 'com.yunlu.greendao.gen'  
//设置DaoMaster、DaoSession、Dao目录
    targetGenDir 'src/main/java'
}
dependencies {
    //greenDao  数据库
    compile 'org.greenrobot:greendao:3.2.0'
}

三、创建一个User的实体类(数据表对应的bean文件)

@Entity
public class User {
    @Id(autoincrement = true)
    private Long id;
    private String name;
    private int age;
    private String pic;
    private String content;
    private String updateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date());//设置默认值为当前时间
}

@Entity:将我们的java普通类变为一个能够被greenDAO识别的数据库类型的实体类
@Id:通过这个注解标记的字段必须是Long类型的,这个字段在数据库中表示它就是主键,并且它默认就是自增的(设置了数值后,下一条数据会自动继续加一)
autoincrement = true使用自增长策略
@NotNull:此字段不能为空
@Index(unique = true) //设置为唯一主键
当前,entity必须有一个long或者Long的属性作为主键,但是有时候我们的主键不一定是long或者Long型的可能是string呀之类的,这个时候我们就可以定义索引属性并且注明独一无二。 如下:

@Index(name = "keyword", unique = true)
private String key;

name用于指明这个索引的列名,unique表示这个指是不可重复的。
执行Build->Make Model app ,会自动根据配置在项目中对应的com.yunlu.greendao.gen目录下生成DaoMaster、DaoSession、UserDao三个文件
四、GreenDao使用

public class MyApplication extends Application {

        private DaoMaster.DevOpenHelper mHelper;
        private SQLiteDatabase db;
        private DaoMaster mDaoMaster;
        private DaoSession mDaoSession;
        public static MyApplication instances;

        @Override
        public void onCreate() {
            super.onCreate();
            instances = this;
            setDatabase();
        }
        public static MyApplication getInstances(){
            return instances;
        }
        private void setDatabase() {
    // 通过 DaoMaster 的内部类 DevOpenHelper,你可以得到一个便利的 SQLiteOpenHelper 对象。
    // 可能你已经注意到了,你并不需要去编写「CREATE TABLE」这样的 SQL 语句,因为 greenDAO 已经帮你做了。
    // 注意:默认的 DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。
    // 所以,在正式的项目中,你还应该做一层封装,来实现数据库的安全升级。
            mHelper = new DaoMaster.DevOpenHelper(this, "notes.db", null);
            db = mHelper.getWritableDatabase();
            // 注意:该数据库连接属于 DaoMaster,所以多个 Session 指的是相同的数据库连接。
            mDaoMaster = new DaoMaster(db);
            mDaoSession = mDaoMaster.newSession();
        }
        public DaoSession getDaoSession() {
            return mDaoSession;
        }
        public SQLiteDatabase getDb() {
            return db;
        }
    }

DevOpenHelper有两个重载方法:
•DevOpenHelper(Context context,String name)
•DevOpenHelper(Context context,String name,CursorFactory factory)
context上下文这个不用多说,name数据库的名字,cursorFactory游标工厂,一般不用,传入null或者使用两个参数的方法即可。我们对外提供一个getDaoSession()的方法供外部使用。
1.unique() // 返回唯一结果或者 null
2.list() // 返回结果集进内存
3.long count() // 获取结果数量

获取UserDao对象:

UserDao mUserDao = MyApplication.getInstances().getDaoSession().getUserDao();

(1)orderAsc:升序排序
(2)orderDesc: 降序排序
(3)eq():==
(4)noteq():!=
(5)gt(): >
(6)lt():<
(7)ge:>=
(8)le:<=
(9)like():包含 (模糊查询) "%"+string+"%"
(10)isNotNull:不为空
“whereOr” where语句里面写的条件都是用“且”连接,whereOr里的语句使用“或”连接
“distinct” 直接过滤掉重负字段
“limit” 分页n个一页,一般和offset结合使用
“offset” 忽略查询出的前n条结果
“preferLocalizedStringOrder” 本地化字符串排序
“orderCustom” 自定义排序 里面需要传两个参数: 一个属性 和对应的排序方案 ASC 或是 DESC
“orderRaw” 也是自定义排序, 把字段和 排序方案 写在一个字符串传入
“stringOrderCollation” 也是自定义排序 可以合并多个升降排序方案 以日期升序 且 价格降序
“notEq” 和eq相反,别傻傻在再去外面敲“!”取反
“notIn” 同上
“or” 或者
“between” 也就是BETWEEN ? AND ? 可以取两个值的区间 (但是这条语句要慎用,不同的数据库不一样,有的是A<条件<B,有的是A<=条件<=B)
“gt” 相当于 >
“ge”相当于 >=
“lt” 相当于 <
“le”相当于 <=
“isNull” 为空

userList = mUserDao.queryBuilder()
                        .where(UserDao.Properties.UserName.like("%"+filterStr+"%"))
                        .list();

(10)between:俩者之间
(11)in:在某个值内 (匹配数组中的某一个)
(12)notIn:不在某个值内
简单的增删改查实现:

mUser = new User();
mUser.setName("wqtest");
try {
    mUserDao.insert(mUser);    //插入数据时主键数据重复时会抛出异常,挂掉
}catch (Exception e){
    Log.d("e", String.valueOf(e));
}
•插入一组数据
List<MovieCollect> listMovieCollect;
mMovieCollectDao.insertInTx(listMovieCollect);
•插入或替换数据
//插入的数据如果已经存在表中,则替换掉旧数据(根据主键来检测是否已经存在)
MovieCollect movieCollect;
mMovieCollectDao.insertOrReplace(movieCollect);//单个数据

List<MovieCollect> listMovieCollect;
mMovieCollectDao.insertOrReplace(listMovieCollect);//一组数据

2.删
•deleteBykey(Long key) :根据主键删除一条记录。
•delete(User entity) :根据实体类删除一条记录,一般结合查询方法,查询出一条记录之后删除。
•deleteAll(): 删除所有记录。
•删除一组数据
List<MovieCollect> listMovieCollect;
mMovieCollectDao.deleteInTx(listMovieCollect);

List users = mUserDao.queryBuilder()
               .where(TabUserDao.Properties.SiteCode.eq(user.getSiteCode()),TabUserDao.Properties.UserCode.eq(user.getUserCode()))
               .list();
       if (users!=null &&users.size()==1){
           try {
               mUserDao.delete((TabUser) users.get(0));
           }catch (Exception e){
               Log.d("e", String.valueOf(e));
           }
       }

3.改
•update(User entity):更新一条记录
•修改一组数据
List<MovieCollect> listMovieCollect;
mMovieCollectDao.updateInTx(listMovieCollect);
4.查
•loadAll():查询所有记录
•load(Long key):根据主键查询一条记录
•queryBuilder().list():返回:List
•queryBuilder().where(UserDao.Properties.Name.eq("")).list():返回:List
•queryRaw(String where,String selectionArg):返回:List

and/or
//and
//查询电影年份大于2012年且电影名以“我的”开头的电影
List<MovieCollect> movieCollect = mMovieCollectDao.queryBuilder().and(MovieCollectDao.Properties.Year.gt(2012), MovieCollectDao.Properties.Title.like("我的%")).list();

//or
//查询电影年份小于2012年或者大于2015年的电影
List<MovieCollect> movieCollect = mMovieCollectDao.queryBuilder().or(MovieCollectDao.Properties.Year.lt(2012), MovieCollectDao.Properties.Year.gt(2015)).list();

//按LoginTime倒序排序,查出时间最近的一条数据
       List<TabUser> tabUsers = mUserDao.queryBuilder().orderDesc(TabUserDao.Properties.LoginTime).list();
       User user = null;
       if (tabUsers!=null &&tabUsers.size()>0){
           return getUserInfo(tabUsers.get(0));
       }
//分组查询
List<User> userList = mUserDao.queryBuilder()
                        .orderDesc(UserDao.Properties.Id)
                        .offset(3)     //从第3条开始 (从0开始数)                      
                       .limit(4).list();   //查询4条数据
(99,88,77,66,55,44,33,22,11)查出来是:(66,55,44,33)
//利用sql语句查询(单列去重)
 Cursor c = mUserDao.getDatabase().rawQuery("SELECT distinct SITE_NAME FROM USER", null);

•缓存问题

由于GreenDao默认开启了缓存,所以当你调用A查询语句取得X实体,然后对X实体进行修改并更新到数据库,接着再调用A查询语句取得X实体,会发现X实体的内容依旧是修改前的。其实你的修改已经更新到数据库中,只是查询采用了缓存,所以直接返回了第一次查询的实体。
解决方法:查询前先清空缓存,清空方法如下
//清空所有数据表的缓存数据
DaoSession daoSession = DaoManager.getInstance().getDaoSession();
daoSession .clear();

//清空某个数据表的缓存数据
MovieCollectDao movieCollectDao = DaoManager.getInstance().getDaoSession().getMovieCollectDao();
movieCollectDao.detachAll();

升级

1.新建MyOpenHelper.Java

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) {
        //切记不要调用super.onUpgrade(db,oldVersion,newVersion)
        if (oldVersion < newVersion) {
            MigrationHelper.migrate(db,TabUserDao.class);//所修改表或新建表
            MigrationHelper.migrate(db,TabTestDao.class);
        }
    }
}

2.Javabean数据表类加相应的字段
3.MyApplication中用MyOpenHelper替代DaoMaster.DevOpenHelper
4.build.gradle中升级数据库版本
附件

package com.msd.standard.Taiguo.greendao;

import android.database.Cursor;
import android.support.annotation.NonNull;
import android.text.TextUtils;

import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.internal.DaoConfig;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 类名:MigrationHelper
 * 类描述:用于数据库升级的工具类
 * 创建日期: 2017/9/26.
 * 版本:V1.0
 */

public class MigrationHelper {
    /**
     * 调用升级方法
     * @param db
     * @param daoClasses 一系列dao.class
     */
    public static void migrate(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        //1 新建临时表
        generateTempTables(db, daoClasses);
        //2 创建新表
        createAllTables(db, false, daoClasses);
        //3 临时表数据写入新表,删除临时表
        restoreData(db, daoClasses);
    }


    /**
     * 生成临时表,存储旧的表数据
     * @param db
     * @param daoClasses
     */
    private static void generateTempTables(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;
            if (!checkTable(db,tableName))
                continue;
            String tempTableName = daoConfig.tablename.concat("_TEMP");
            StringBuilder insertTableStringBuilder = new StringBuilder();
            insertTableStringBuilder.append("alter table ")
                    .append(tableName)
                    .append(" rename to ")
                    .append(tempTableName)
                    .append(";");
            db.execSQL(insertTableStringBuilder.toString());
        }
    }

    /**
     * 检测table是否存在
     * @param db
     * @param tableName
     */
    private static Boolean checkTable(Database db,String  tableName){
        StringBuilder query = new StringBuilder();
        query.append("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='").append(tableName).append("'");
        Cursor c = db.rawQuery(query.toString(), null);
        if (c.moveToNext()){
            int count = c.getInt(0);
            if(count>0){
                return true;
            }
            return false;
        }
        return false;
    }

    /**
     * 删除所有旧表
     * @param db
     * @param ifExists
     * @param daoClasses
     */
    private static void dropAllTables(Database db, boolean ifExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
        reflectMethod(db, "dropTable", ifExists, daoClasses);
    }

    /**
     * 创建新的表结构
     * @param db
     * @param ifNotExists
     * @param daoClasses
     */
    private static void createAllTables(Database db, boolean ifNotExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
        reflectMethod(db, "createTable", ifNotExists, daoClasses);
    }

    /**
     * 创建根删除都在NoteDao声明了,可以直接拿过来用
     * dao class already define the sql exec method, so just invoke it
     */
    private static void reflectMethod(Database db, String methodName, boolean isExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
        if (daoClasses.length < 1) {
            return;
        }
        try {
            for (Class cls : daoClasses) {
                //根据方法名,找到声明的方法
                Method method = cls.getDeclaredMethod(methodName, Database.class, boolean.class);
                method.invoke(null, db, isExists);
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 临时表的数据写入新表
     * @param db
     * @param daoClasses
     */
    private static 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");
            if (!checkTable(db,tempTableName))
                continue;
            // get all columns from tempTable, take careful to use the columns list
            List<String> columns = getColumns(db, tempTableName);
            //新表,临时表都包含的字段
            ArrayList<String> properties = new ArrayList<>(columns.size());
            for (int j = 0; j < daoConfig.properties.length; j++) {
                String columnName = daoConfig.properties[j].columnName;
                if (columns.contains(columnName)) {
                    properties.add(columnName);
                }
            }
            if (properties.size() > 0) {
                final String columnSQL = TextUtils.join(",", properties);

                StringBuilder insertTableStringBuilder = new StringBuilder();
                insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
                insertTableStringBuilder.append(columnSQL);
                insertTableStringBuilder.append(") SELECT ");
                insertTableStringBuilder.append(columnSQL);
                insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");
                db.execSQL(insertTableStringBuilder.toString());
            }
            StringBuilder dropTableStringBuilder = new StringBuilder();
            dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
            db.execSQL(dropTableStringBuilder.toString());
        }
    }

    private static List<String> getColumns(Database db, String tableName) {
        List<String> columns = null;
        Cursor cursor = null;
        try {
            cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 0", null);
            if (null != cursor && cursor.getColumnCount() > 0) {
                columns = Arrays.asList(cursor.getColumnNames());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null)
                cursor.close();
            if (null == columns)
                columns = new ArrayList<>();
        }
        return columns;
    }

}

上一篇下一篇

猜你喜欢

热点阅读