zoukankan      html  css  js  c++  java
  • GreenDao 数据库:使用Raw文件夹下的数据库文件以及数据库升级

    一、使用Raw文件夹下的数据库文件

    在使用GreenDao框架时,数据库和数据表都是根据生成的框架代码来自动创建的,从生成的DaoMaster中的OpenHelper类可以看出:

    public static abstract class OpenHelper extends SQLiteOpenHelper {
    
            public OpenHelper(Context context, String name, CursorFactory factory) {
                super(context, name, factory, SCHEMA_VERSION);
            }
    
            @Override
            public void onCreate(SQLiteDatabase db) {
                Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION);
           //修改第二个参数为true
    createAllTables(db,
    false); } }

    对应的createAllTables函数代码:

    /** Creates underlying database table using DAOs. */
        public static void createAllTables(SQLiteDatabase db, boolean ifNotExists) {
            xxxxxDao.createTable(db, ifNotExists);
        }

    再接着往下看:

    /** Creates the underlying database table. */
        public static void createTable(SQLiteDatabase db, boolean ifNotExists) {
            String constraint = ifNotExists? "IF NOT EXISTS ": "";
            db.execSQL("CREATE TABLE " + constraint + "'DOCTOR' (" + //
                    "'_id' INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id
                    "'NAME' TEXT," + // 1: name
                   
        }

    从以上的代码可以看出GreenDao在第一次使用的时候会强制创建数据表,如果这样的话很可能就会导致程序崩溃。

    public static abstract class OpenHelper extends SQLiteOpenHelper {
    
            public OpenHelper(Context context, String name, CursorFactory factory) {
                super(context, name, factory, SCHEMA_VERSION);
            }
    
            @Override
            public void onCreate(SQLiteDatabase db) {
                Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION);
           //修改第二个参数为true
    
                createAllTables(db, true);
            }
        }

    所以要使用Raw文件中的数据库文件需要以下几步:

      1)修改参数:

    public static abstract class OpenHelper extends SQLiteOpenHelper {
    
            public OpenHelper(Context context, String name, CursorFactory factory) {
                super(context, name, factory, SCHEMA_VERSION);
            }
    
            @Override
            public void onCreate(SQLiteDatabase db) {
                Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION);
           //修改第二个参数为true
    
                createAllTables(db, true);
            }
        }

      2)添加GreenDaoContextWrapper.java文件到项目中

    public class GreenDaoContextWrapper extends ContextWrapper {

    private Context mContext;

    public GreenDaoContextWrapper(Context base) {
    super(base);
    this.mContext= base;
    }

    @Override
    public File getDatabasePath(String name) {
    Log.d("GreenDao","getDatabasePath");
    Log.d("GreenDao",mContext.getDatabasePath(name).getAbsolutePath());
    String filePath=mContext.getDatabasePath(name).getAbsolutePath();
    File file=new File(filePath);
    if (!file.exists()){
    buildDatabase(filePath);
    }
    return file;
    }
      
    /**
    * 创建数据库文件,其实就是将raw文件夹下的数据库文件复制到应用的database文件夹下:
    * /data/data/com.xxxx/databases/
    * @param filePath
    */

    private void buildDatabase(String filePath){
            Log.d("GreenDao","buildDatabase");
    InputStream inputStream=mContext.getResources().openRawResource(R.raw.accurmedicine);
    FileOutputStream fos= null;
    try {
    fos = new FileOutputStream(filePath);
    byte[] buffer=new byte[1024];
    int length;
    while ((length=inputStream.read(buffer))>0){
    fos.write(buffer,0,length);
    }
    fos.close();
    inputStream.close();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    @Override
    public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) {
    Log.d("GreenDao","openOrCreateDatabase");
    SQLiteDatabase result= SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name),factory);
    return result;
    }

    @Override
    public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
    Log.d("GreenDao","openOrCreateDatabase");
    SQLiteDatabase result= SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name),factory);
    return result;
    }
    }

    这里提一下:ContextWrapper是一个Context包装类,需要包含一个真正的Context,详细介绍看:

    http://www.jianshu.com/p/94e0f9ab3f1d

      3)在创建DevOpenHelper的时候使用GreenDaoContextWrapper

    String DBName="xxx";
    DaoMaster.DevOpenHelper helper=new DaoMaster.DevOpenHelper(new GreenDaoContextWrapper(context),DBName,null);

    这样就大功告成了!

    二、数据库版本升级

    这个办法是从网上看到的,还不错,就搬过来了。

    public class MigrationHelper {
    
        private static MigrationHelper instance;
    
        public static MigrationHelper getInstance() {
            if (instance==null){
                instance=new MigrationHelper();
            }
            return instance;
        }
    
        /**
         * 创建临时表->删除旧表->创建新表->导入数据
         * @param database
         * @param daoClasses
         */
        public void migrate(SQLiteDatabase database, Class<? extends AbstractDao<?,?>>...daoClasses){
            generateTempTables(database,daoClasses);
            DaoMaster.dropAllTables(database,true);
            DaoMaster.createAllTables(database,false);
            restoreData(database,daoClasses);
        }
    
        /**
         * 临时表生产
         * @param database
         * @param daoClasses
         */
        private void generateTempTables(SQLiteDatabase database,Class<? extends AbstractDao<?,?>>...daoClasses){
            for (int i=0;i<daoClasses.length;i++){
                DaoConfig config=new DaoConfig(database,daoClasses[i]);
                String divider="";
                String tableName=config.tablename;
                String tmpTableName=config.tablename.concat("_TEMP");
                ArrayList<String > properties=new ArrayList<>();
                StringBuilder createTableStringBuilder=new StringBuilder();
                createTableStringBuilder.append("CREATE TABLE ").append(tmpTableName).append(" (");
                List<String> columns = getColumns(database, tableName);
                for (int j=0;j<config.properties.length;j++){
                    String columnName=config.properties[j].columnName;
                    if (columns.contains(columnName)){
                        properties.add(columnName);
                        String type=null;
                        try {
                            type=getTypeByClass(config.properties[j].type);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);
                        if (config.properties[j].primaryKey){
                            createTableStringBuilder.append("  PRIMARY KEY");
                        }
                        divider=",";
                    }
                }
                createTableStringBuilder.append(");");
                Log.d("xxxxx","sql="+createTableStringBuilder.toString());
                database.execSQL(createTableStringBuilder.toString());
                StringBuilder insertTableString=new StringBuilder();
                insertTableString.append("insert into ").append(tmpTableName).append(" (");
                insertTableString.append(TextUtils.join(",",properties));
                insertTableString.append(") select ");
                insertTableString.append(TextUtils.join(",",properties));
                insertTableString.append(" from ").append(tableName).append(";");
                Log.d("xxxxx","sql="+insertTableString.toString());
                database.execSQL(insertTableString.toString());
            }
        }
    
        /**
         * 数据字段与Java数据类型匹配
         * @param type
         * @return
         * @throws Exception
         */
        private String getTypeByClass(Class<?> type) throws Exception {
            if (type.equals(String.class)){
                return "TEXT";
            }
            if (type.equals(Long.class)||type.equals(Integer.class)){
                return "INTEGER";
            }
            if (type.equals(Boolean.class)){
                return "BOOLEAN";
            }
            String strException="数据表数据类型匹配错误";
            Exception exception=new Exception(strException.concat("- Class").concat(type.toString()));
            throw exception;
        }
    
        /**
         * 获取当前数据表字段列表
         * @param database
         * @param tableName
         * @return
         */
        private static List<String > getColumns(SQLiteDatabase database,String tableName){
            List<String > columns=new ArrayList<>();
            Cursor cursor=null;
            /**
             * 通过查询数据表
             */
            cursor=database.rawQuery("select * from "+tableName+" limit 1",null);
            try {
                if (cursor!=null){
                    String[] columnNames = cursor.getColumnNames();
                    for (String name:columnNames){
                        columns.add(name.toUpperCase());
                    }
    //                columns=new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                if (cursor!=null){
                    cursor.close();
                }
            }
            return columns;
        }
    
        /**
         * 数据恢复->删除临时表
         * @param database
         * @param daoClasses
         */
        private void restoreData(SQLiteDatabase database,Class<? extends AbstractDao<?,?>>...daoClasses){
            for (int i=0;i<daoClasses.length;i++){
                DaoConfig config=new DaoConfig(database,daoClasses[i]);
                String tableName=config.tablename;
                String tmpTableName=config.tablename.concat("_TEMP");
                ArrayList<String > properties=new ArrayList<>();
                for (int j=0;j<config.properties.length;j++){
                    String columnName = config.properties[j].columnName;
    
                    if(getColumns(database, tmpTableName).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(tmpTableName).append(";");
    
                StringBuilder dropTableStringBuilder = new StringBuilder();
    
                dropTableStringBuilder.append("DROP TABLE ").append(tmpTableName);
    
                database.execSQL(insertTableStringBuilder.toString());
                database.execSQL(dropTableStringBuilder.toString());
            }
        }
    
    }

    然后在需要数据库版本设计的时候修改DaoMaster中的SCHEMA_VERSION 

    public static final int SCHEMA_VERSION = 1;

    这个变量就是用于在创建OpenHelper时指定数据库版本号。

    紧接着修改DevOpenHelper的onUpgrade代码:

     @Override
            public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
                Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
    //            dropAllTables(db, true);
    //            onCreate(db);
                MigrationHelper.getInstance()
                        .migrate(db,
                        paramsDao.class,
                        );
            }

    最后大功告成!

     顺带需要补充一下,查看SQLite数据库版本可以执行以下这句语句:

    PRAGMA user_version

    设置SQLite数据库版本的语句:

    PRAGMA user_version =<你的版本号>

    以上的这两句话其实可以在SQLiteDatabase以及SQLiteOpenHelper的源码中看到:

    在android-24的SQLiteOpenHelper源码中可以看到:

    /**
         * Gets the database version.
         *
         * @return the database version
         */
        public int getVersion() {
            return ((Long) DatabaseUtils.longForQuery(this, "PRAGMA user_version;", null)).intValue();
        }
    
        /**
         * Sets the database version.
         *
         * @param version the new database version
         */
        public void setVersion(int version) {
            execSQL("PRAGMA user_version = " + version);
        }

    而SQLiteOpenHelper设置和获取数据库版本就是通过调用这两句话来实现的,具体源码可以查看SQLiteOpenHelper的getDatabaseLocked函数,这里不再赘述。

  • 相关阅读:
    Java连接Oracle数据库
    团队冲刺阶段(八)
    团队冲刺阶段(七)
    团队冲刺进度(六)
    团队冲刺进度(五)
    团队冲刺进度(四)
    团队冲刺进度(三)
    团队冲刺进度(二)
    团队冲刺进度(一)
    软件需求规格所明书
  • 原文地址:https://www.cnblogs.com/libertycode/p/6256000.html
Copyright © 2011-2022 走看看