你的位置:首页 > 操作系统

[操作系统]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函数,这里不再赘述。