- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我正在评估 GreenDAO 以考虑在我将要开发的商业 Android 应用中考虑,并希望确定架构更新的迁移路径。
我是否正确断言我必须编写一个自定义 OpenHelper,它提供 onUpdate() 并根据新模式提取转换和存储数据?这个假设提出了一些关于调用顺序和责任划分的有趣问题。
我找不到任何有关 GreenDAO 架构更新和数据迁移的文档。
这是我写的关于这个主题的大量博客文章:
最佳答案
考虑到 pleonasmik 的方法(顺便说一句,谢谢,这真的很有帮助),我创建了一个 MigrationHelper 类。
它是如何工作的:
generateTempTables
方法)generateTempTables
方法)DaoMaster.dropAllTables
方法)DaoMaster.createAllTables
方法)restoreData
方法)restoreData
方法)迁移助手类:
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;
import android.util.Log;
import com.crashlytics.android.Crashlytics;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import de.greenrobot.dao.AbstractDao;
import de.greenrobot.dao.internal.DaoConfig;
import greendao.DaoMaster;
/**
* Created by pokawa on 18/05/15.
*/
public class MigrationHelper {
private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";
private static MigrationHelper instance;
public static MigrationHelper getInstance() {
if(instance == null) {
instance = new MigrationHelper();
}
return instance;
}
public void migrate(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
generateTempTables(db, daoClasses);
DaoMaster.dropAllTables(db, true);
DaoMaster.createAllTables(db, false);
restoreData(db, daoClasses);
}
private void generateTempTables(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
for(int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String divider = "";
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList<String> properties = new ArrayList<>();
StringBuilder createTableStringBuilder = new StringBuilder();
createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");
for(int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if(getColumns(db, tableName).contains(columnName)) {
properties.add(columnName);
String type = null;
try {
type = getTypeByClass(daoConfig.properties[j].type);
} catch (Exception exception) {
Crashlytics.logException(exception);
}
createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);
if(daoConfig.properties[j].primaryKey) {
createTableStringBuilder.append(" PRIMARY KEY");
}
divider = ",";
}
}
createTableStringBuilder.append(");");
db.execSQL(createTableStringBuilder.toString());
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(" FROM ").append(tableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
}
}
private void restoreData(SQLiteDatabase 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");
ArrayList<String> properties = new ArrayList();
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if(getColumns(db, tempTableName).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(tempTableName).append(";");
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
db.execSQL(insertTableStringBuilder.toString());
db.execSQL(dropTableStringBuilder.toString());
}
}
private String getTypeByClass(Class<?> type) throws Exception {
if(type.equals(String.class)) {
return "TEXT";
}
if(type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class)) {
return "INTEGER";
}
if(type.equals(Boolean.class)) {
return "BOOLEAN";
}
Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));
Crashlytics.logException(exception);
throw exception;
}
private static List<String> getColumns(SQLiteDatabase db, String tableName) {
List<String> columns = new ArrayList<>();
Cursor cursor = null;
try {
cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
if (cursor != null) {
columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
}
} catch (Exception e) {
Log.v(tableName, e.getMessage(), e);
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return columns;
}
}
下面是一个在 DaoMaster.java 类中应该如何调用它的示例:
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by migrating all tables data");
MigrationHelper.getInstance().migrate(db,
UserDao.class,
ItemDao.class);
}
关于android - GreenDAO 架构更新和数据迁移?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13373170/
问题是:GreenDao什么时候从session缓存中更新sql数据库? 假设我正在从数据库中查询现有实体,而不是更改其中一个属性(字段)。无论如何,这些更改都是在不指导 sql 数据库的情况下执行的
我有一个现有的 sqlite db 架构(大约 30 个表),我必须将其导入到我的 Android 项目中。 我想在我的代码中使用 greenDao,但如果我已经创建了 sqlite db,我不知道这
如何为一个实体创建多个表? 最佳答案 在 greenDAO 中是不可能的,目前也没有计划支持此功能。你能解释一下你为什么要这样做以及这应该如何工作吗?也许有更好的方法... 关于greendao -
我在我的 Android 项目中使用 GreenDAO。 我已经实现了一个增量更改表,因此我可以跟踪对实体的各个更新。我想在一个“updateTask”方法中跟踪这些更改,因此无论从何处调用它,都可以
我有以下问题: 是否可以使用GreenDao 进行跨平台应用?例如,在桌面和 Android 上运行的应用程序。 有哪些替代方案? 在GreenDao中MasterDao的包是什么? 谁能举个真实的数
我正在使用 greendao 3.2 并制作实体和数据库。它一切正常。 但是在创建必须自动递增的 Id 属性时我遇到了麻烦。我知道如何在 SQL 中做到这一点,但使用 greendao 它给了我更多的
我只需要使用 GreenDao 返回一列。这是 SQL 查询: SELECT NAME FROM PERSON 如何使用 GreenDao 做到这一点? 最佳答案 如果您想执行原始查询(DaoSess
使用 GreenDao,我以某种方式设法将我的数据库置于一个没有 key 的实体的状态。 我的问题是如何清除/删除该实体?我在 AbstractDao 中没有看到可以让我删除另一个列名的函数。 最佳答
我想使用 GreenDao 构建以下查询。 select * from luckydrawclick e where e.user = ? and (e.id = ? or e.id = ? or e
如何在不使用字符串操作的 toLowercase/toUppercase 的情况下使字符串比较不区分大小写 QueryBuilder qb = mPropertyModelDao.queryBuild
我使用以下代码来定义两个通过一对多关系相关的实体。 private static void addLuckyDrawClick(Schema schema) { Entity luckyDra
我有一个具有 3 个一对多关系的实体 private List Data1; private List Data2; private List Data3; 我想在手动创建的列表中总结这些数据(Tot
我已经阅读了 greendao 文档,但没有找到任何关于在由于某种原因实体更新失败时发出警告的方法的线索...... update(T entity) 既不返回任何东西也不抛出任何错误... 那么有什
在我的应用程序中,我有一个 Entity/table,它有一个 Name 字段(在其他几个字段中)。我想要在该表中找到的所有唯一名称的字符串列表。 现在我唯一能想到的就是将所有结果加载到实体对象列表中
我想知道如何获取我的数据库(当然是 *.sqlite 文件)大小(以字节为单位)? 我目前的做法(行不通)是: 新文件(DataManager.getInstance().db.getPath()).
我一直在寻找解决我的问题的方法,但没有成功。 我有一个应用程序,在该应用程序中,我从不同的服务接收数据库中特定实体的信息,因此我使用 greenDAOs insertOrReplace 方法,因此只要
我正在使用 green dao,我已经到了支持多语言的地步,我想为每种语言使用不同的数据库。 到目前为止,我一直在使用 green dao 创建我的数据库。现在我想在 assets 中有多个数据库,只
我有一个具有 500 个属性的实体,每个属性都有人类可修改的名称,例如“serialNumber”,但它的 column_name 是“E_A_XNF”。 现在我有一个表单,它为我提供了一个以列名作为
我是 greenDao(第 3 版)的新手。我有一个带有状态字段的表。我有一个 ID 列表。我想使用 ID 将所有状态更新为“Activity ”。我未能获得此更新的任何此类方法。谁能帮我解决这个问题
我正在尝试使用 greendao 创建两个相同结构的表。所以基本上,我正在做以下事情来实现。创建 Position.class: public class Position { protect
我是一名优秀的程序员,十分优秀!