Android GreenDao 升级 保留旧表数据

Android GreenDao 升级 保留旧表数据

大川的川关注IP属地: 北京

0.2052019.08.05 11:54:36字数 270阅读 363

瓦力和伊娃

GreenDao升级库版本号之后,以前的旧数据没有了,为啥,因为GreenDao在升级的时候会删除旧库,创建新库,就问你,到这里,脑袋是不是嗡嗡的?!
********别着急,有答案!亲测可用,非常完美~********
查阅资料得到了满意的答案!如下:
  • 第一项: 新建一个MigrationHelper类,它主要是通过创建一个临时表,将旧表的数据迁移到新表中。
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.database.StandardDatabase;
import org.greenrobot.greendao.internal.DaoConfig;import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;/*** * please call {@link #migrate(SQLiteDatabase, Class[])} or {@link #migrate(Database, Class[])}* */
public final class MigrationHelper {public static boolean DEBUG = false;private static String TAG = "MigrationHelper";private static final String SQLITE_MASTER = "sqlite_master";private static final String SQLITE_TEMP_MASTER = "sqlite_temp_master";private static WeakReference<ReCreateAllTableListener> weakListener;public interface ReCreateAllTableListener{void onCreateAllTables(Database db, boolean ifNotExists);void onDropAllTables(Database db, boolean ifExists);}public static void migrate(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {printLog("【The Old Database Version】" + db.getVersion());Database database = new StandardDatabase(db);migrate(database, daoClasses);}public static void migrate(SQLiteDatabase db, ReCreateAllTableListener listener, Class<? extends AbstractDao<?, ?>>... daoClasses) {weakListener = new WeakReference<>(listener);migrate(db, daoClasses);}public static void migrate(Database database, ReCreateAllTableListener listener, Class<? extends AbstractDao<?, ?>>... daoClasses) {weakListener = new WeakReference<>(listener);migrate(database, daoClasses);}public static void migrate(Database database, Class<? extends AbstractDao<?, ?>>... daoClasses) {printLog("【Generate temp table】start");generateTempTables(database, daoClasses);printLog("【Generate temp table】complete");ReCreateAllTableListener listener = null;if (weakListener != null) {listener = weakListener.get();}if (listener != null) {listener.onDropAllTables(database, true);printLog("【Drop all table by listener】");listener.onCreateAllTables(database, false);printLog("【Create all table by listener】");} else {dropAllTables(database, true, daoClasses);createAllTables(database, false, daoClasses);}printLog("【Restore data】start");restoreData(database, daoClasses);printLog("【Restore data】complete");}private static void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {for (int i = 0; i < daoClasses.length; i++) {String tempTableName = null;DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);String tableName = daoConfig.tablename;if (!isTableExists(db, false, tableName)) {printLog("【New Table】" + tableName);continue;}try {tempTableName = daoConfig.tablename.concat("_TEMP");StringBuilder dropTableStringBuilder = new StringBuilder();dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName).append(";");db.execSQL(dropTableStringBuilder.toString());StringBuilder insertTableStringBuilder = new StringBuilder();insertTableStringBuilder.append("CREATE TEMPORARY TABLE ").append(tempTableName);insertTableStringBuilder.append(" AS SELECT * FROM `").append(tableName).append("`;");db.execSQL(insertTableStringBuilder.toString());printLog("【Table】" + tableName +"\n ---Columns-->"+getColumnsStr(daoConfig));printLog("【Generate temp table】" + tempTableName);} catch (SQLException e) {Log.e(TAG, "【Failed to generate temp table】" + tempTableName, e);}}}private static boolean isTableExists(Database db, boolean isTemp, String tableName) {if (db == null || TextUtils.isEmpty(tableName)) {return false;}String dbName = isTemp ? SQLITE_TEMP_MASTER : SQLITE_MASTER;String sql = "SELECT COUNT(*) FROM `" + dbName + "` WHERE type = ? AND name = ?";Cursor cursor=null;int count = 0;try {cursor = db.rawQuery(sql, new String[]{"table", tableName});if (cursor == null || !cursor.moveToFirst()) {return false;}count = cursor.getInt(0);} catch (Exception e) {e.printStackTrace();} finally {if (cursor != null)cursor.close();}return count > 0;}private static String getColumnsStr(DaoConfig daoConfig) {if (daoConfig == null) {return "no columns";}StringBuilder builder = new StringBuilder();for (int i = 0; i < daoConfig.allColumns.length; i++) {builder.append(daoConfig.allColumns[i]);builder.append(",");}if (builder.length() > 0) {builder.deleteCharAt(builder.length() - 1);}return builder.toString();}private static void dropAllTables(Database db, boolean ifExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {reflectMethod(db, "dropTable", ifExists, daoClasses);printLog("【Drop all table by reflect】");}private static void createAllTables(Database db, boolean ifNotExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {reflectMethod(db, "createTable", ifNotExists, daoClasses);printLog("【Create all table by reflect】");}/*** 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();}}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 (!isTableExists(db, true, tempTableName)) {continue;}try {// get all columns from tempTable, take careful to use the columns listList<TableInfo> newTableInfos = TableInfo.getTableInfo(db, tableName);List<TableInfo> tempTableInfos = TableInfo.getTableInfo(db, tempTableName);ArrayList<String> selectColumns = new ArrayList<>(newTableInfos.size());ArrayList<String> intoColumns = new ArrayList<>(newTableInfos.size());for (TableInfo tableInfo : tempTableInfos) {if (newTableInfos.contains(tableInfo)) {String column = '`' + tableInfo.name + '`';intoColumns.add(column);selectColumns.add(column);}}// NOT NULL columns listfor (TableInfo tableInfo : newTableInfos) {if (tableInfo.notnull && !tempTableInfos.contains(tableInfo)) {String column = '`' + tableInfo.name + '`';intoColumns.add(column);String value;if (tableInfo.dfltValue != null) {value = "'" + tableInfo.dfltValue + "' AS ";} else {value = "'' AS ";}selectColumns.add(value + column);}}if (intoColumns.size() != 0) {StringBuilder insertTableStringBuilder = new StringBuilder();insertTableStringBuilder.append("REPLACE INTO `").append(tableName).append("` (");insertTableStringBuilder.append(TextUtils.join(",", intoColumns));insertTableStringBuilder.append(") SELECT ");insertTableStringBuilder.append(TextUtils.join(",", selectColumns));insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");db.execSQL(insertTableStringBuilder.toString());printLog("【Restore data】 to " + tableName);}StringBuilder dropTableStringBuilder = new StringBuilder();dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);db.execSQL(dropTableStringBuilder.toString());printLog("【Drop temp table】" + tempTableName);} catch (SQLException e) {Log.e(TAG, "【Failed to restore data from temp table 】" + tempTableName, e);}}}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;}private static void printLog(String info){if(DEBUG){Log.d(TAG, info);}}private static class TableInfo {int cid;String name;String type;boolean notnull;String dfltValue;boolean pk;@Overridepublic boolean equals(Object o) {return this == o|| o != null&& getClass() == o.getClass()&& name.equals(((TableInfo) o).name);}@Overridepublic String toString() {return "TableInfo{" +"cid=" + cid +", name='" + name + '\'' +", type='" + type + '\'' +", notnull=" + notnull +", dfltValue='" + dfltValue + '\'' +", pk=" + pk +'}';}private static List<TableInfo> getTableInfo(Database db, String tableName) {String sql = "PRAGMA table_info(`" + tableName + "`)";printLog(sql);Cursor cursor = db.rawQuery(sql, null);if (cursor == null)return new ArrayList<>();TableInfo tableInfo;List<TableInfo> tableInfos = new ArrayList<>();while (cursor.moveToNext()) {tableInfo = new TableInfo();tableInfo.cid = cursor.getInt(0);tableInfo.name = cursor.getString(1);tableInfo.type = cursor.getString(2);tableInfo.notnull = cursor.getInt(3) == 1;tableInfo.dfltValue = cursor.getString(4);tableInfo.pk = cursor.getInt(5) == 1;tableInfos.add(tableInfo);// printLog(tableName + ":" + tableInfo);}cursor.close();return tableInfos;}}
}
  • 第二项: 新建一个UpgradeOpenHelper类,继承DaoMaster.DevOpenHelper,重写onUpgrade(Database db, int oldVersion, int newVersion)方法,在该方法中使用MigrationHelper进行数据库升级以及数据迁移。
public class UpgradeOpenHelper extends DaoMaster.OpenHelper {public UpgradeOpenHelper (Context context, String name, SQLiteDatabase.CursorFactory factory) {super(context, name, factory);}@Overridepublic void onUpgrade(Database db, int oldVersion, int newVersion) {//把需要管理的数据库表DAO作为最后一个参数传入到方法中MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() {@Overridepublic void onCreateAllTables(Database db, boolean ifNotExists) {DaoMaster.createAllTables(db, ifNotExists);}@Overridepublic void onDropAllTables(Database db, boolean ifExists) {DaoMaster.dropAllTables(db, ifExists);}},  Test1Dao.class,Test2Dao.class,Test3Dao.class,Test4Dao.class);}
}
  • 第三项: 然后使用UpgradeOpenHelper替代DaoMaster.DevOpenHelper来进行创建数据库等操作。
upgradeOpenHelper= new UpgradeOpenHelper(MyApplication.getInstance(), DB_NAME, null);//建库
mDaoMaster = new DaoMaster(mSQLiteOpenHelper.getWritableDatabase());
mDaoSession = mDaoMaster.newSession();
  • 第四项:
    修改Module下build.gradle中数据库的版本号schemaVersion ,递增加1即可,最后运行app

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3281382.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【超详细含图】Ubuntu系统忘记root密码的解决方法

1.启动或者重启Ubuntu长按shift进入grub菜单&#xff1b; 选第二个&#xff0c;按住e进入 2.选择recovery mode进入Recovery Menu界面&#xff0c; 选择root Drop to root shell prompt* 3.修改root密码操作&#xff1a; #passwd 输入新密码&#xff1a;# 再输入一遍密码&…

LLM之本地部署GraphRAG(GLM-4+Xinference的embedding模型)(附带ollma部署方式)

前言 有空再写 微软开源的GraphRAG默认是使用openai的接口的&#xff08;GPT的接口那是要money的&#xff09;&#xff0c;于是就研究了如何使用开源模型本地部署。 源码地址&#xff1a;https://github.com/microsoft/graphrag 操作文档&#xff1a;https://microsoft.git…

springBoot+protobuf(全程Protocol Buffers协议)简单入门

了解Protocol Buffers协议 Protocal Buffers是google推出的一种序列化协议&#xff0c;用于结构化的数据序列化、反序列化。 官方解释&#xff1a;Protocol Buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法&#xff0c;它可用于&#xff08;数据&#xff09;通…

鸿蒙(API 12 Beta2版)NDK开发【使用Node-API接口进行异步任务开发】

使用Node-API接口进行异步任务开发 场景介绍 napi_create_async_work是Node-API接口之一&#xff0c;用于创建一个异步工作对象。可以在需要执行耗时操作的场景中使用&#xff0c;以避免阻塞主线程&#xff0c;确保应用程序的性能和响应性能。例如以下场景&#xff1a; 文件…

入门 PyQt6 看过来(案例)17~ 表格

PyQt6提供了两种用于有规律地呈现更多数据的控件&#xff0c;一种是表格结构的控件(QTableView)&#xff0c;另一种是树形结构的控件(QTreeView)。表格控件属于QTableView类&#xff0c;QTableWidget继承于QTableView。 1 QTableView 表格控件 QTableView控件中QStandItemMod…

IT人求职就业手册:如何在数字时代脱颖而出

&#x1f482; 个人网站:【 摸鱼游戏】【网址导航】【神级代码资源网站】&#x1f91f; 一站式轻松构建小程序、Web网站、移动应用&#xff1a;&#x1f449;注册地址&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交…

【CodinGame】趣味算法(教学用) CLASH OF CODE -20240731

文章目录 正文闰年偶数和密码塔楼高度 写在最后END 正文 闰年 import sys import math# Auto-generated code below aims at helping you parse # the standard input according to the problem statement.a int(input()) b int(input()) count0 for i in range(a, b 1):if…

DELL服务器RAID配置详细教程

DELL服务器RAID配置教程 在启动电脑的时候按CTRLR 进入 RAID 设置见面如下图 名称解释&#xff1a; Disk Group&#xff1a;磁盘组&#xff0c;这里相当于是阵列&#xff0c;例如配置了一个RAID5&#xff0c;就是一个磁盘组 VD(Virtual Disk)&#xff1a; 虚拟磁盘&#xff…

开启智能开发的新纪元:探索 GPT-4o mini 模型的无限可能

引言 随着人工智能技术的飞速发展&#xff0c;大型语言模型已成为推动软件开发和创新的关键力量。OpenAI 最新发布的 GPT-4o mini 模型以其卓越的性能和极具竞争力的价格&#xff0c;为开发者社区带来了新的活力。本文将探讨 GPT-4o mini 模型的特性&#xff0c;以及它如何帮助…

K8S第二节:kubeadm搭建K8s集群

上回书说到什么是K8s&#xff0c;这回就在我自己的虚拟机上搭建一个K8s集群; 一、安装K8S需要的软件包 yum install -y kubelet-1.23.1 kubeadm-1.23.1 kubectl-1.23.1 其中&#xff1a; kubelet:是K8s集群中每个node节点上的管家&#xff0c;用来处理Master节点下发到本节点的…

深入源码:解析SpotBugs (5)BugReportor

常见的 Bug 定位后&#xff0c;通过 bugReport的reportBug&#xff08;BugInstance&#xff09; 方法&#xff0c;将bug 发布出来。 一般的 Detector 经检测后会调用 bugReportor.reportBug 方法或者 BugAccumulator.accumulateBug 。 在GUI中&#xff0c;分析结束后会在下框…

楼宇智能化仿真实训室解决方案

在信息技术的浪潮中&#xff0c;智慧城市作为未来城市发展的新形态&#xff0c;正以前所未有的速度在全球范围内兴起。其中&#xff0c;楼宇智能化作为智慧城市的关键构成&#xff0c;扮演着举足轻重的角色。它不仅提升了建筑的能源效率、安全性与舒适度&#xff0c;还促进了城…

WIFI7:引领智能驾驶新未来

近年来&#xff0c;智能驾驶技术飞速发展&#xff0c;从最初的初级的辅助驾驶逐步迈向高度自动驾驶&#xff0c;这一变化历程深刻依赖的是高效、稳定且前沿的无线通信技术的支撑。WIFI7&#xff0c;作为无线通信领域的最新里程碑&#xff0c;凭借其前所未有的性能提升与功能拓展…

这些才是电脑该装的,5款软件良心且实用,别让它们寒心

为什么别人的电脑&#xff0c;开机无广告&#xff0c;使用0卡顿&#xff0c;下载资源快的飞起&#xff0c;网页就是简洁画面。 而自己的电脑却.....开机超过1%&#xff0c;广告一大堆&#xff0c;下载速度差之千里&#xff0c;网页全是“是兄弟&#xff0c;就来砍我”的船新版…

奥运会被误报的韩国国旗,有多少AI能准确识别?结果出人意料!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…

飞创直线模组桁架机械手优势及应用领域

随着工业自动化和智能制造的发展&#xff0c;直线模组桁架机械手极大地减轻了人类的体力劳动负担&#xff0c;在危险性、重复性高的作业环境中展现出了非凡的替代能力&#xff0c;引领着工业生产向自动化、智能化方向迈进。 一、飞创直线模组桁架机械手优势 飞创直线模组桁架…

Spring Boot集成udp通讯

Spring Boot集成udp通讯 加入依赖编辑配置文件配置相关属性具体业务类客户端调试 加入依赖 <!--加入UDP通信所需依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-integration</artifactId&…

【PCB设计原则5】-PCB设计的寄生元件

寄生电容 在PCB上布两条靠近的走线&#xff0c;很容易形成寄生电容。由于这种电容的存在&#xff0c;在一条走线上的快速电压变化&#xff0c;可在另一条走线上产生电流信号。 设计电路板时&#xff0c;放置两条彼此靠近的走线就会产生寄生电容。例如,在不同的两层&#xff0c…

OJ-0731

题目 题解 参考 import java.util.Arrays; import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner new Scanner(System.in);while (scanner.hasNext()) {int xmh scanner.nextInt();int n scanner.nextInt();int[] COs …

SFP, SFP+,QSFP光模块封装类型

前言&#xff1a; 本文是自己对SFP, SFP,QSFP光模块封装类型的学习记录&#xff0c;所有的资料都搜集字引用链接里的博客内容&#xff0c;本文更多的是自己的学习笔记记录所以可能会有一些理解错误&#xff0c;请更多的参考引用链接里的信息来源。 引用&#xff1a; 认识SFP/SF…