迁移房间数据库时有没有办法使用迁移期间计算的变量?

Posted

技术标签:

【中文标题】迁移房间数据库时有没有办法使用迁移期间计算的变量?【英文标题】:Is there a way when Migrating a Room Database to use Variables that are calculated during the Migration? 【发布时间】:2021-06-17 00:26:30 【问题描述】:

我正在用 Java 编写一个 android 应用程序,并且我已经更改了我的数据库,现在我想将它迁移到新版本,但为此我需要计算一些旧值,然后将它们插入其中一个新表进入数据库但是当我调用时

database.execSQL()

使用我的变量然后访问它们似乎没有设置它们,因为每个值都是 0。

这是不可能的,还是我只是错过了什么?

public void migrate(@NonNull SupportSQLiteDatabase database) 
             database.execSQL("CREATE TABLE 'season' ('id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
                    'spring' INTEGER DEFAULT 0, 'summer' INTEGER DEFAULT 0, 'autumn' INTEGER 
                    DEFAULT 0, 'winter' 
                    INTEGER DEFAULT 0, 'spook' INTEGER DEFAULT 0)");
            database.execSQL("INSERT INTO 'Clothes' (type_of_clothing,clothing_name,description,seasonId,in_laundry,TypeList) " +
                    "SELECT type_of_clothing,clothing_name,description,type_of_clothing,in_laundry,TypeList " +
                    "FROM ClothesNew");
            Cursor cursor = database.query("SELECT * FROM Clothes");
            Cursor secondCursor = database.query("SELECT * FROM ClothesSeason");
            ArrayList<Season> seasonsToBeAdded = new ArrayList<>();
            while (cursor.moveToNext()) 
                secondCursor.moveToNext();
                int Sid = cursor.getInt(0);
                String seasonString = secondCursor.getString(2);
                Season season = new Season(seasonString);
                int tempId = Sid;
                boolean isInList = false;
                for (Season tempSeason : seasonsToBeAdded) 
                    if (tempSeason.equals(season)) 
                        tempId = seasonsToBeAdded.indexOf(tempSeason);
                        isInList = true;
                        break;
                    
                
                if (!isInList) 
                    season.setId(seasonsToBeAdded.size());
                    tempId = season.getId();
                    seasonsToBeAdded.add(season);
                
                if (seasonsToBeAdded.size() == 0) seasonsToBeAdded.add(season);
                
                database.execSQL("UPDATE Clothes SET seasonId = :tempId WHERE uid = :Sid");
            

            int id, spring, summer, autumn, winter, spook;

            for (Season season : seasonsToBeAdded) 
                id = season.getId();
                spring = season.getSpring();
                summer = season.getSummer();
                autumn = season.getAutumn();
                winter = season.getWinter();
                spook = season.getSpook();
                database.execSQL("INSERT INTO season " +
                        "VALUES(:id, :spring, :summer, :autumn, :winter, :spook) ");
            
            Cursor otherCursor = database.query("SELECT * FROM season");
            ArrayList<Integer> springValues= new ArrayList<>();
            while (otherCursor.moveToNext()) 
                springValues.add(otherCursor.getInt(1));
            
        

当我查看存储在 springValues 中的值时,即使我在此查询中添加了正确的值,它们也都是 0

database.execSQL("INSERT INTO season " +
                 "VALUES(:id, :spring, :summer, :autumn, :winter, :spook) ");

我可以不在这里使用 :var 符号吗?

【问题讨论】:

【参考方案1】:

我建议使用 SQLiteDatabase Insert 便捷方法和 ContentValues 对象。

而不是:-

        for (Season season : seasonsToBeAdded) 
            id = season.getId();
            spring = season.getSpring();
            summer = season.getSummer();
            autumn = season.getAutumn();
            winter = season.getWinter();
            spook = season.getSpook();
            database.execSQL("INSERT INTO season " +
                    "VALUES(:id, :spring, :summer, :autumn, :winter, :spook) ");
        

您的代码可能是:-

    ContentValues cv = new ContentValues(); // Instantiate ContentValues object
    for (Season season : seasonsToBeAdded) 
        cv.clear();
        cv.put("`id`",season.getId());
        cv.put("`spring`",season.getSpring());
        cv.put("`summer`",season.getSummer());
        cv.put("`autumn`",season.getAutumn());
        cv.put("`winter`",season.getWinter());
        cv.put("`spook`",season.getSpook());
        database.insert("season",null,cv); //<<<< Recommended Uses the convenience Insert Method

请注意,列名不必像上面使用的那样用重音 `` 括起来。

以上代码为in-principal code,未经测试,可能存在一些错误。

如您所见,SQL 是为您构建的。 insert 方法返回插入行的 rowid(id 列),如果插入失败则返回 -1,您可能希望利用该值。

您可能还希望使用其他插入方法,例如insertWithOnConflict 例如database.insertWithOnConflict("season",null,cv,SQLiteDatabase.CONFLICT_IGNORE);

还建议通过使用适当的 SQLiteDatabase 事务处理方法来利用事务(请参阅beginTransaction)

还建议您对列名使用常量,以便在适当的位置对名称进行编码。列名错误的可能性很小。

【讨论】:

以上是关于迁移房间数据库时有没有办法使用迁移期间计算的变量?的主要内容,如果未能解决你的问题,请参考以下文章

(Android) 房间数据库迁移不会改变数据库

仅向多个表的主键添加 @NonNull 注释的房间迁移

Android 房间迁移测试失败,但没有任何改变

在 Android 中使用房间数据库写入迁移的查询错误

房间迁移:“没有这样的表:room_table_modification_log”

由于房间中的唯一约束,数据库迁移失败