美文网首页Android 理论
GreenDao3.0简单使用2

GreenDao3.0简单使用2

作者: 禄子_c79b | 来源:发表于2018-12-12 17:22 被阅读0次
        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;
        }
    
    }
    
    

    相关文章

      网友评论

        本文标题:GreenDao3.0简单使用2

        本文链接:https://www.haomeiwen.com/subject/ccyphqtx.html