关于“升级到 Room 2.2.0 时处理列默认值”的困惑?

Che*_*eng 4 android android-room

我指的是https://developer.android.com/training/data-storage/room/migrating-db-versions.md#handle-default-values-migrations

我对指南感到困惑。我的理解是

如果添加NON NULL新列

@Entity
public class Song {
    // ...
    @NonNull
    final String tag;
}
Run Code Online (Sandbox Code Playgroud)

使用以下ALTER TABLE迁移策略是错误的


错误的

static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL(
            "ALTER TABLE Song ADD COLUMN tag TEXT NOT NULL DEFAULT ''");
    }
};
Run Code Online (Sandbox Code Playgroud)

您需要使用以下drop and re-create迁移策略

正确的

static final Migration MIGRATION_2_3 = new Migration(2, 3) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("CREATE TABLE new_Song (" +
                "id INTEGER PRIMARY KEY NOT NULL," +
                "name TEXT," +
                "tag TEXT NOT NULL DEFAULT '')");
        database.execSQL("INSERT INTO new_Song (id, name, tag) " +
                "SELECT id, name, tag FROM Song");
        database.execSQL("DROP TABLE Song");
        database.execSQL("ALTER TABLE new_Song RENAME TO Song");
    }
};
Run Code Online (Sandbox Code Playgroud)

这甚至让我感到困惑。不是这两种方法,最终都会有相同的列 - tag TEXT NOT NULL DEFAULT ''?前一种方法如何标记为有问题的方法?

有人可以提供一个简单的例子,解释使用 可能会出现什么问题ALTER TABLE,以及如何drop and re-create克服这个问题?

谢谢。

Che*_*eng 6

通过https://issuetracker.google.com/issues/137515134与原作者讨论后 ,这里有一个简单易懂的例子。


版本 1,房间 2.1.0

@Entity
public class Song {
    @PrimaryKey
    final long id;
}
Run Code Online (Sandbox Code Playgroud)

版本 2,房间 2.1.0(添加 @NonNull)

@Entity
public class Song {
    @PrimaryKey
    final long id;
    @NonNull
    final String tag;
}

static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL(
            "ALTER TABLE Song ADD COLUMN tag TEXT NOT NULL DEFAULT ''");
    }
};
Run Code Online (Sandbox Code Playgroud)

版本 3,Room 2.2.0(将 Room 升级到 2.2.0,添加了 @ColumnInfo)

@Entity
public class Song {
    @PrimaryKey
    final long id;
    @ColumnInfo(defaultValue = "")
    @NonNull
    final String tag;
}

static final Migration MIGRATION_2_3 = new Migration(2, 3) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("CREATE TABLE new_Song (" +
                "id INTEGER PRIMARY KEY NOT NULL," +
                "tag TEXT NOT NULL DEFAULT '')");
        database.execSQL("INSERT INTO new_Song (id, tag) " +
                "SELECT id, tag FROM Song");
        database.execSQL("DROP TABLE Song");
        database.execSQL("ALTER TABLE new_Song RENAME TO Song");
    }
};
Run Code Online (Sandbox Code Playgroud)

读者须知

  1. 数据库版本 2(从未经历过 MIGRATION_1_2)在其 SQLite 架构中没有 DEFAULT ''。需要 MIGRATION_2_3。

  2. 数据库版本 2(已经通过 MIGRATION_1_2)在其 SQLite 模式中有 DEFAULT ''。MIGRATION_2_3 没有危害。

  3. 在 SQLite 中,无法更改列以添加 DEFAULT '' 约束。