【问题标题】:ORMLite update of the database数据库的ORMLite更新
【发布时间】:2012-12-08 21:24:25
【问题描述】:

我实际上正在开发一个使用 ORMLite 库的应用程序(顺便说一句,这很棒),但我是使用它的初学者。

我有一个关于设备内部数据库更新的问题。

假设有人在 Google Play 上下载了我的应用。几个月后,我肯定会用新条目填充一些表格。

当这个人更新应用程序时,我怎样才能用我的新条目更新数据库并将旧条目保留在其中。

为了更清楚,假设用户在我的应用中回答了问题。当我将介绍新问题时,我如何在他更新我的应用程序时将它们插入到数据库中并保留已经回答的问题

【问题讨论】:

    标签: android database ormlite


    【解决方案1】:

    当这个人更新应用程序时,我怎样才能用我的新条目更新数据库并将旧条目保留在其中。

    这个想法是使用传递给onUpgrade(...) 方法的版本号。对于ORMLiteOrmLiteSqliteOpenHelper.onUpgrade(...) 方法采用oldVersionnewVersion 数字。然后,您可以将转换代码写入您的应用程序,该代码能够从旧格式转换数据并更新架构。

    有关详细信息,请参阅ORMLite docs on upgrading your schema

    引用,您可以执行以下操作:

    if (oldVersion < 2) {
      // we added the age column in version 2
      dao.executeRaw("ALTER TABLE `account` ADD COLUMN age INTEGER;");
    }
    if (oldVersion < 3) {
      // we added the weight column in version 3
      dao.executeRaw("ALTER TABLE `account` ADD COLUMN weight INTEGER;");
    }
    

    如果您有需要转换的现有数据,那么您应该尽可能在 SQL 中进行转换。

    另一种选择是让Account 实体和OldAccount 实体指向同一个表名。然后您可以使用oldAccountDao 读取OldAccount 实体,将它们转换为Account 实体,然后使用accountDao 将它们更新回同一个表。您需要注意这里的对象缓存。

    【讨论】:

    • 我接受这一点,因为我已经设法通过在 Db 版本上执行 switch 语句并根据每个 db 版本添加/删除数据来解决这个问题。
    • 当您“在版本 3 中添加权重列”时,if 检查是否需要为oldVersion &lt; 3?因为否则,数据库版本 2 将无法获得 weight 列。
    • 哎呀,你是对的@saschoar。我已经编辑了我的答案。谢谢。
    • 没问题(也值得更新文档示例吗?)——无论如何,感谢您所做的出色工作。
    • 我不想依赖 Jodatime @ChrisNevill,所以它是可选的。如果您有任何问题,请使用用户列表。 DateTime 以 Long 形式存储在数据库中:github.com/j256/ormlite-core/blob/master/src/main/java/com/j256/…
    【解决方案2】:

    我是这样做的:

    @Override
    public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
    
        switch (oldVersion) {
        case 1:
            updateFromVersion1(database, connectionSource, oldVersion, newVersion);
            break;
        case 2:
            updateFromVersion2(database, connectionSource, oldVersion, newVersion);
            break;
        default:
            // no updates needed
            break;
        }
    
    }
    
    private void updateFromVersion1(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
        // do some stuff here
        onUpgrade(database, connectionSource, oldVersion + 1, newVersion);
    }
    
    private void updateFromVersion2(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
        // do some stuff here
        onUpgrade(database, connectionSource, oldVersion + 1, newVersion);
    }
    

    这将独立于他即将到来的数据库版本增量更新用户数据库。

    【讨论】:

    • 如果你删除断句并在开头移动默认值,你就不需要递归调用
    • 在 Room Sqlite 这样我们可以将数据从旧版本迁移到新版本?
    【解决方案3】:

    资料不多,不清楚你的表结构是否有变化。

    a)如果不改变数据库结构。

    1 在您的程序的新版本中,当您开始检查以前保存的版本时(例如在首选项中) 与当前(参见 PackageManager.getPackageInfo)

    saved = 0 - 用户刚刚安装了新版本

    已保存

    2 将新数据添加到基础

    3 保存当前版本的首选项

    b)如果表结构发生变化(添加或删除字段)

    1 增加你的数据库的版本号(见你的扩展 OrmLiteSqliteOpenHelper 类)

    2 当用户首次运行您的程序时,将调用方法“onUpgrade”(在您的扩展 OrmLiteSqliteOpenHelper 类中),该方法将转移到旧版本号和新版本号。

    • 读取缓存中的现有数据(临时)
    • 重新创建表
    • 从缓存中添加数据 + 您的新数据

    【讨论】:

    • 好的,感谢您的澄清,但我的问题是如何读取缓存中的现有数据并按照您所说的将它们与新数据一起添加?
    【解决方案4】:

    我不喜欢在每次升级时删除数据库,或者在添加每个字段后编写更新代码,所以...

    我正在尝试这样做:

    @Override
    public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
        ArrayList<String> tableNames = getTableNames(database);
        for (Class clazz : daoClasses) {
            try {
                Annotation annotation = clazz.getAnnotation(DatabaseTable.class);
                if (annotation != null && annotation instanceof DatabaseTable) {
                    String tableName = ((DatabaseTable) annotation).tableName();
                    if (tableName.isEmpty()) {
                        tableName = clazz.getSimpleName().substring(0, 1).toLowerCase() + clazz.getSimpleName().substring(1);
                    }
                    if(!tableNames.contains(tableName)){
                        TableUtils.createTable(connectionSource, clazz);
                    } else {
                        addColumns(database, tableName, clazz);
                    }
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
    
    private ArrayList<String> getTableNames(SQLiteDatabase database){
        ArrayList<String> tableNames = new ArrayList<>();
        Cursor cursor = database.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null);
        if (cursor.moveToFirst()) {
            while ( !cursor.isAfterLast() ) {
                tableNames.add(cursor.getString(0));
                cursor.moveToNext();
            }
        }
        cursor.close();
        return tableNames;
    }
    
    private void addColumns(SQLiteDatabase database, String tableName, Class clazz){
        Cursor mCursor = database.rawQuery("SELECT * FROM " + tableName + " LIMIT 0", null);
        for (Field field : clazz.getDeclaredFields()) {
            try {
                DatabaseField annotationField = field.getAnnotation(DatabaseField.class);
                if (annotationField != null && !annotationField.foreign()){
                    String columnName = field.getName();
                    boolean hasColumn = mCursor.getColumnIndex(columnName) != -1;
                    if (!hasColumn) {
                        String columnType = field.getType().getSimpleName();
                        if(columnType.equals(String.class.getSimpleName())){
                            columnType = "TEXT";
                        } else {
                            columnType = columnType.toUpperCase();
                        }
                        database.execSQL(MessageFormat.format("ALTER TABLE `{0}` ADD COLUMN {1} {2};", tableName, columnName, columnType));
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        mCursor.close();
    }
    

    希望这段代码可以更好。

    在这里,我不会删除从 dao 中删除的旧表和列,也不会创建外部字段(我不确定是否需要)。

    【讨论】:

    • 谢谢!我将在我的第一个带有 SQLite + ORMLite 的 Android 应用程序中尝试它。您的 daoClasses 列表是否像这样手动定义: List daoClasses = Arrays.asList( (Class) MyDaoClass.class, (Class)AnOtherDaoClass.class) ?跨度>
    • 您应该在String tableName = ((DatabaseTable) annotation).tableName(); 之后添加if(tableName.isEmpty()) tableName=clazz.getSimpleName().substring(0,1).toLowerCase()+clazz.getSimpleName().substring(1); 以管理DatabaseTable 不包含任何tableName 的情况(默认表名是类的simpleName,第一个字符为小写。
    • @Elloco ty 进行改进。 Daoclasses 是:private static final Class[] daoClasses = {A.class,B.class,C.class};
    猜你喜欢
    • 1970-01-01
    • 2014-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多