当前位置: 首页 > 知识库问答 >
问题:

在使用房间版本2.4.0-alpha01中提供的当前自动迁移功能的同时,向现有房间数据库添加列

党祖鹤
2023-03-14

我有一个包含数据的房间数据库,现在我想再增加一列。

房间版本2.4.0-alpha01及以上应该使自动迁移更容易,所以我这样使用它:

...
version = 2,
autoMigrations = {
        @AutoMigration(from = 1, to = 2)
        }, 
exportSchema = true

然后在我的模型类中,我添加了新的列名,并生成了它的setters和getters,就像其他的一样。

文件室文档指出,如果文件室由于复杂的模式更改而无法执行迁移,则会抛出编译时错误。然而,在我的例子中,我得到了一个关于预期模式和新模式(我在其中添加了一列)之间差异的运行时错误。

以下是错误:

java.lang.RuntimeException: Exception while computing database live data.
        at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:92)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:919)
     Caused by: java.lang.IllegalStateException: Migration didn't properly handle: accounts(com.bisform.susu.models.Account).
     Expected:
    TableInfo{name='accounts', columns={accountSavings=Column{name='accountSavings', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountName=Column{name='accountName', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountCreateTime=Column{name='accountCreateTime', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, numberOfDeposits=Column{name='numberOfDeposits', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, accountNumber=Column{name='accountNumber', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, numberOfWithdrawals=Column{name='numberOfWithdrawals', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, accountPayoutDate=Column{name='accountPayoutDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, phoneOfNextOfKin=Column{name='phoneOfNextOfKin', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountImageURI=Column{name='accountImageURI', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountID=Column{name='accountID', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}, lastUpdatedDate=Column{name='lastUpdatedDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, phoneNumber=Column{name='phoneNumber', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountPayoutTime=Column{name='accountPayoutTime', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, lastUpdatedTime=Column{name='lastUpdatedTime', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, nameOfNextOfKin=Column{name='nameOfNextOfKin', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountCreateDate=Column{name='accountCreateDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, isPaidOut=Column{name='isPaidOut', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
     Found:
E/AndroidRuntime: TableInfo{name='accounts', columns={accountSavings=Column{name='accountSavings', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountName=Column{name='accountName', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountCreateTime=Column{name='accountCreateTime', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, numberOfDeposits=Column{name='numberOfDeposits', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, accountNumber=Column{name='accountNumber', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, numberOfWithdrawals=Column{name='numberOfWithdrawals', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, accountPayoutDate=Column{name='accountPayoutDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountImageURI=Column{name='accountImageURI', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountID=Column{name='accountID', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}, lastUpdatedDate=Column{name='lastUpdatedDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, phoneNumber=Column{name='phoneNumber', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountPayoutTime=Column{name='accountPayoutTime', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, lastUpdatedTime=Column{name='lastUpdatedTime', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountCreateDate=Column{name='accountCreateDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, isPaidOut=Column{name='isPaidOut', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
        at androidx.room.RoomOpenHelper.onUpgrade(RoomOpenHelper.java:103)
...

请问我应该如何处理此错误?如何使用当前提供的自动迁移功能获得正确迁移的空间?

共有2个答案

易英奕
2023-03-14

解决上述问题所需要的只是清理项目和重建。我想旧的模式不知何故还在内存中,因此崩溃了。

李经国
2023-03-14

请问我应该如何处理此错误?如何使用当前提供的自动迁移功能获得正确迁移的空间?

我相信只有在忽略自动迁移的情况下,您才会得到这个结果。对于您展示的代码,我认为唯一的方法是包括手动迁移,因为这将覆盖自动迁移。

如下所示的测试表明了这一点。

测试

此测试显示覆盖从V1到V2的自动迁移的效果,以及未覆盖时迁移的工作方式。

该测试基于根据预期(v2)和发现(v1)消息构建的Accounts类。

因此Accounts类是:-

@Entity(tableName = "accounts")
class Accounts {

    //String phoneOfNextOfKin; //<<<<< For  V2 else commented out
    //String nameOfNextOfKin; //<<<<< for V2 else commented out

    String accountSavings;
    String accountName;
    String accountCreateTime;
    Integer numberOfDeposits;
    String accountNumber;
    int numberOfWithdrawals;
    String accountPayoutDate;
    String accountImageURI;
    @PrimaryKey
    Long accountId;
    String lastUpdatedDate;
    String phoneNumber;
    String accountPayoutTime;
    String lastUpdatedTime;
    String accountCreateDate;
    boolean isPaidOut;
}
  • 注意到带有注释的行//

在版本之间不会更改的@Dao类:-

@Dao
abstract class AccountsDao {
    @Insert
    abstract long insert(Accounts accounts);
    @Query("SELECT * FROM accounts")
    abstract List<Accounts> getAllFromAccounts();
}

@Database类:-

@Database(
        entities = {Accounts.class},
        version = TheDatabase.DBVERSION
        /* following line, if no schema saved, needs to be commented out */
        , autoMigrations = {@AutoMigration(from = 1, to = 2)} 
)
abstract class TheDatabase extends RoomDatabase {
    abstract AccountsDao getAccountsDao();

    public static final int DBVERSION = 1; //<<<<< change accordingly

    private static volatile TheDatabase instance = null;

    static TheDatabase getInstance(Context context) {
        if (instance == null) {
            instance = Room.databaseBuilder(
                    context,
                    TheDatabase.class,
                    "accounts.db"
            )
                    .allowMainThreadQueries() //run on main thread for brevity and convenience
                    .addMigrations(MIGRATION_1_2) //<<<<< if included then Migration didn't properly handle:
                    .build();
        }
        return instance;
    }

    /* Only needed for creating error shown in question */
    /* doesn't hurt if no addMigrations or when creating V1 */
    static final Migration MIGRATION_1_2 = new Migration(1,2) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {

        }
    };
}

最后,开展下列活动:-

public class MainActivity extends AppCompatActivity {

    TheDatabase db;
    AccountsDao dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        db = TheDatabase.getInstance(this);
        dao = db.getAccountsDao();

        Accounts a = new Accounts();
        a.accountCreateDate = "2021-01-01";
        a.accountCreateTime = "08:00:00";
        a.accountImageURI = "imageURI";
        a.accountName = "MyAccount";
        a.accountNumber = "0000000000";
        a.accountPayoutDate = "2021-05-05";
        a.accountPayoutTime = "10:00:00";
        a.accountSavings = "savings";
        a.lastUpdatedDate = "2021-05-03";
        a.lastUpdatedTime = "09:15:00";
        a.numberOfDeposits = 10;
        a.numberOfWithdrawals = 5;
        a.isPaidOut = false;

        //a.nameOfNextOfKin = "Mr Next of Kin"; //<<<<< For V2
        //a.phoneOfNextOfKin = "1111111111"; //<<<<< For V2

        dao.insert(a);
        for(Accounts account: dao.getAllFromAccounts()) {
            String msg = "Account is " + account.accountName + " ID is " + account.accountId;
            if (TheDatabase.DBVERSION > 1) {
                //msg = msg + " next of kin is " + account.nameOfNextOfKin; //<<<<< For V2
            }
            Log.d("ACCOUNTINFO", msg);
        }
    }
}

运行和结果:-

  1. 使用上述代码(不包括V2代码),且未安装应用程序。i、 e.创建V1数据库:-

>

  • 应用程序成功运行,数据库检查器显示:-

    架构和单行一样是预期的。

    • 应用程序成功运行,数据库检查器显示:-

    3.为转到V2所做的更改:-

    >

    在数据库DBVERSION从1更改为2和. addMigrations保留包括

    在调用活动中,名称和近亲值被赋值,而不是被注释掉。msg变量被连接以包括近亲。

    应用程序崩溃

    :-

    Caused by: java.lang.IllegalStateException: Migration didn't properly handle: accounts(a.a.so69442030javaroomautomigrationsaddcolumns.Accounts).
         Expected:
    2021-10-05 14:31:50.669 30268-30268/a.a.so69442030javaroomautomigrationsaddcolumns E/AndroidRuntime: TableInfo{name='accounts', columns={accountSavings=Column{name='accountSavings', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountName=Column{name='accountName', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountCreateTime=Column{name='accountCreateTime', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, numberOfDeposits=Column{name='numberOfDeposits', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountNumber=Column{name='accountNumber', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, numberOfWithdrawals=Column{name='numberOfWithdrawals', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, phoneOfNextOfKin=Column{name='phoneOfNextOfKin', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountPayoutDate=Column{name='accountPayoutDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountImageURI=Column{name='accountImageURI', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountId=Column{name='accountId', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}, lastUpdatedDate=Column{name='lastUpdatedDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, phoneNumber=Column{name='phoneNumber', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountPayoutTime=Column{name='accountPayoutTime', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, nameOfNextOfKin=Column{name='nameOfNextOfKin', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, lastUpdatedTime=Column{name='lastUpdatedTime', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountCreateDate=Column{name='accountCreateDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, isPaidOut=Column{name='isPaidOut', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
         Found:
    2021-10-05 14:31:50.670 30268-30268/a.a.so69442030javaroomautomigrationsaddcolumns E/AndroidRuntime: TableInfo{name='accounts', columns={accountSavings=Column{name='accountSavings', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountName=Column{name='accountName', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountCreateTime=Column{name='accountCreateTime', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, numberOfDeposits=Column{name='numberOfDeposits', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountNumber=Column{name='accountNumber', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, numberOfWithdrawals=Column{name='numberOfWithdrawals', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, accountPayoutDate=Column{name='accountPayoutDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountImageURI=Column{name='accountImageURI', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountId=Column{name='accountId', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}, lastUpdatedDate=Column{name='lastUpdatedDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, phoneNumber=Column{name='phoneNumber', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountPayoutTime=Column{name='accountPayoutTime', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, lastUpdatedTime=Column{name='lastUpdatedTime', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, accountCreateDate=Column{name='accountCreateDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, isPaidOut=Column{name='isPaidOut', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
            at androidx.room.RoomOpenHelper.onUpgrade(RoomOpenHelper.java:103)
    
    • i、 e.复制遇到的故障

    步骤1-2在卸载应用程序并按照V1使用代码后重新运行(从头开始演示整个过程)(用注释掉或删除的. addMigrations重新运行将克服这个问题)

    按照第3步进行的更改被应用,但是另外,数据库构建中的. addMigrations行被注释掉了。

    • 应用程序不会崩溃。Database inspector在新插入的行中显示修改后的架构和适当的数据(另外两个添加的列为空):-

  •  类似资料:
    • 并且我发现了基于数据库版本4的可能场景的迁移varargs。 我的问题是,假设我使用的是db v1的Room,当我的应用程序到达db v10时,我将不得不编写多少迁移方法? 在sqlite中,我们在中获得已安装应用程序的当前db版本,我们只需通过开关大小写而不使用break语句,以便满足所有db升级。

    • 在构建Room数据库之前,我尝试保留旧的SqliteOpenHelper并使用它从1升级到3。这在第一次运行时有效,但随后的运行会使SqliteOpenHelper崩溃,因为它不能降级数据库(Room成功升级到v4,但open helper只知道v3。使用它来确保升级到v3的数据库会导致它尝试降级)

    • 我在存钱 进入我的房间数据库版本1。 现在我需要将

    • 已经创建了一个@Embedded类播放器。我想在其中添加ArrayList字段,该字段使用@TypeConverters,它在保存时将列表转换为Gson,在加载时将其转换为Gson。请告诉我如何在void migrate() 方法中请求将列表添加到Player类的现有实例中。 类保存: TypeConverter:

    • 我转换java代码到kotlin代码,我得到类型未解决的java类错误。 我的Java类是 已转换的Kotlin类 非常感谢。

    • 我正在使用2.4.0-ALPHA01房间