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函数,这里不再赘述。
GreenDao 数据库:使用Raw文件夹下的数据库文件以及数据库升级的更多相关文章
- php 读取网页源码 , 导出成txt文件, 读取xls,读取文件夹下的所有文件的文件名
<?php // 读取网页源码$curl = curl_init();curl_setopt($curl, CURLOPT_URL, $url);curl_setopt($curl, CURLO ...
- C#实现把指定文件夹下的所有文件复制到指定路径下以及修改指定文件的后缀名
1.实现把指定文件夹下的所有文件复制到指定路径下 public static void copyFiles(string path) { DirectoryInfo dir = new Directo ...
- C/C++不同文件夹下包含头文件的方法及#include的使用
转自:http://blog.sina.com.cn/s/blog_6e0693f70100so42.html 本文主要介绍了如何不同文件夹下使用预处理器指示符#include. 假设我们有如下一个工 ...
- 递归输出文件夹下的所有文件的名称(转自 MSDN)
问题:如何输出给定文件夹目录下面的所有文件的名称? C#代码: using System; using System.IO; namespace MyTest { public class Progr ...
- IO流的练习3 —— 复制多级文件夹下的指定文件并改名
需求:复制指定目录下的指定文件,并修改后缀名. 指定的文件是:.java文件. 指定的后缀名是:.jad 数据源所在文件夹:C:\Users\Administrator\Desktop\记录 目的地所 ...
- C/C++遍历Windows文件夹下的所有文件
因为文件夹中往往包含文件和文件夹.想要遍历所有的文件,必须遍历文件夹中所有的文件夹.很显然,这个描述满足递归的两个要素:(1)问题的规模在不断的缩小,且新问题的模式与旧问题相同.很显然文件夹中含有子文 ...
- JAVA 遍历文件夹下的所有文件
JAVA 遍历文件夹下的所有文件(递归调用和非递归调用) 1.不使用递归的方法调用. public void traverseFolder1(String path) { int fileNum = ...
- java读取某个文件夹下的所有文件
import java.io.FileNotFoundException;import java.io.IOException;import java.io.File; public class Re ...
- shell脚本实现查找文件夹下重复的文件,并提供删除功能
Windows下有软件FindDupFile,可以搜索指定目录及其下子目录,列出所有内容完全相同的文件(文件名可能不同),然后由用户选择删除重复的文件. 然而shell脚本却可以使用几行的命令完成与此 ...
- [置顶] LOAD语句:利用MSSQL中的xp_cmdshell功能,将指定文件夹下的指定文件,生成mysql的LOAD语句
LOAD语句:利用MSSQL中的xp_cmdshell功能,将指定文件夹下的指定文件,生成mysql的LOAD语句 declare @sql varchar(4000), @dirpath varch ...
随机推荐
- TODO:小程序开发过程之体验者
TODO:小程序开发过程之体验者 1. 小程序开发过程,先下载开发者并安装开发者工具,现在腾讯开放测试了,普通用户也可以登录开发者工具,如图普通用户登录为调试类型,但是只能建立无AppID的项目 如果 ...
- C# 对象实例化 用json保存 泛型类 可以很方便的保存程序设置
参考页面: http://www.yuanjiaocheng.net/webapi/test-webapi.html http://www.yuanjiaocheng.net/webapi/web-a ...
- [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法
二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...
- 纸箱堆叠 bzoj 2253
纸箱堆叠 (1s 128MB) box [问题描述] P 工厂是一个生产纸箱的工厂.纸箱生产线在人工输入三个参数 n, p, a 之后,即可自动化生产三边边长为 (a mod P, a^2 mod p ...
- MVC还是MVVM?或许VMVC更适合WinForm客户端
最近开始重构一个稍嫌古老的C/S项目,原先采用的技术栈是『WinForm』+『WCF』+『EF』.相对于现在铺天盖地的B/S架构来说,看上去似乎和Win95一样古老,很多新入行的,可能就没有见过经典的 ...
- win7下利用ftp实现华为路由器的上传和下载
win7下利用ftp实现华为路由器的上传和下载 1. Win7下ftp的安装和配置 (1)开始->控制面板->程序->程序和功能->打开或关闭Windows功能 (2)在Wi ...
- SMBus set up a 2-byte EEPROM address for read/write
Sequencer Engine spec: http://www.analog.com/media/en/technical-documentation/data-sheets/ADM1260.pd ...
- (转载)linux下各个文件夹的作用
linux下的文件结构,看看每个文件夹都是干吗用的/bin 二进制可执行命令 /dev 设备特殊文件 /etc 系统管理和配置文件 /etc/rc.d 启动的配置文件和脚本 /home 用户主目录的基 ...
- Disque:Redis之父新开源的分布式内存作业队列
Disque是Redis之父Salvatore Sanfilippo新开源的一个分布式内存消息代理.它适应于"Redis作为作业队列"的场景,但采用了一种专用.独立.可扩展且具有容 ...
- ASP.NET MVC 描述类型(一)
ASP.NET MVC 描述类型(一) 前言 在前面的好多篇幅中都有提到过ControllerDescriptor类型,并且在ASP.NET MVC 过滤器(一)篇幅中简单的描述过,今天我们就来讲一下 ...