将数据从 sqlite 数据库文件移动到房间
Move data from sqlite database file to room
我有一个处理外部数据库(sqlite数据库文件)的项目,我想移动到房间数据库如下
- 数据库 (student_database.db) 的内容最初由第三方应用程序输入,例如(DB Browser for SQLite)。
- 当我 运行 我的应用程序创建了数据库空间并将数据从 student_database.db
3 我的应用程序在 Recycler View 中显示来自 (room db) 的数据
- 新数据可以添加到数据库(房间)
这是我项目的一些文件
@Entity(tableName = "books_table")
public class Book {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "book_id")
private long id;
@ColumnInfo(name = "book_name")
private String name;
@ColumnInfo(name = "all")
private long all;
@ColumnInfo(name = "profile_id")
private long profileId;
public Book() {
}
public Book(String name, long all, long profileId) {
this.name = name;
this.all = all;
this.profileId = profileId;
}
@Dao
public interface BookDAO {
@Insert
void insertBook(Book... book);
@Update
void updateBook(Book... book);
@Entity (tableName = "profiles_table")
public class Profile {
@PrimaryKey(autoGenerate = true)
long id;
@ColumnInfo (name = "profile_name")
String profileName;
public Profile() {
}
public Profile(long id, String profileName) {
this.id = id;
this.profileName = profileName;
}
public Profile(String profileName) {
this.profileName = profileName;
}
@Dao
public interface ProfileDAO {
@Insert
void insertProfile(Profile... profile);
@Update
void updateProfile(Profile... profile);
@Database(entities = {Book.class , Profile.class}, version = 1, exportSchema = false)
public abstract class MyRoomDatabase extends RoomDatabase {
public abstract BookDAO bookDao();
public abstract ProfileDAO profileDAO();
private static volatile MyRoomDatabase INSTANCE;
private static final int NUMBER_OF_THREADS = 4;
static final ExecutorService databaseWriteExecutor =
Executors.newFixedThreadPool(NUMBER_OF_THREADS);
static MyRoomDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
synchronized (MyRoomDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
MyRoomDatabase.class, "student_prepare_room_database")
.addCallback(sRoomDatabaseCallback)
.build();
}
}
}
return INSTANCE;
}
private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
// If you want to keep data through app restarts,
// comment out the following block
databaseWriteExecutor.execute(() -> {
// Populate the database in the background.
// If you want to start with more words, just add them.
});
}
};
}
student_database.db
CREATE TABLE "profile_table" ("id" INTEGER,"profile_name" TEXT,PRIMARY KEY("id"));
[1]: https://i.stack.imgur.com/lDhtR.png
CREATE TABLE "books_table" ("book_id" INTEGER,"book_name" TEXT,"all" INTEGER,"profile_id" INTEGER,PRIMARY KEY("book_id" AUTOINCREMENT));
[2]: https://i.stack.imgur.com/NiuZe.png
通常,这将通过使外部数据库成为资产(预打包的数据库)并利用 .createFromAsset
来进行,后者将进行数据库的复制。
但是,使用上面的 REQUIRE 资产数据库严格符合由 classes 定义的房间模式 @Entity
并包含在通过 @Database
注释提供的实体 list/array 中。
可以使用prePackagedDatabaseCallback
修改预打包的数据库来适配。但是,对外部数据库进行更改以使其符合房间的预期可能更简单。
在您的情况下,例如,您在 配置文件 table 中不匹配,因为在 external/pre-packaged 数据库中您有 id 作为(有效地)INTEGER PRIMARY KEY
而通过使用 @PrimaryKey(autoGenerate = true)
房间期望 INTEGER PRIMARY KEY AUTOINCREMENT
.
AUTOINCREMENT
(在房间 autogenerate = true
中)效率低下且很少需要。您可以改为使用 @PrimaryKey
.
让房间变得简单
只讨论了一个不匹配的例子,因为很可能没有必要深入研究所有会导致问题的不匹配。当用 @Entity
注释的 classes 已经创建并包含在 classes 的列表中时,当您编译项目时,空间将生成预期的 CREATE TABLE ....
语句@Database
注释。因此,您可以根据 room.
创建的 SQL 轻松地对 external/pre-packaged table 进行必要的更改。
Room创建的SQL在java(generated)中找到(在Android View)m,要查找的 class 与 class 同名,注释为 @Database
但后缀为 _Impl。 SQL 在名为 createAllTables
的方法中找到。您不想创建 room_master_table,它是一个 table,room 用于存储模式的哈希表示,并用于检查是否已对模式进行更改。
演示
根据您的问题使用 code/schemas(进行一些细微的更改以简化演示)。
第 1 步 - 根据您的模式预打包数据库
- 显然你有这个
首先,根据您的 SQL 创建了一个数据库,并在第三方工具 (Navicat) 中填充了大约 100 个配置文件和 10000 本书:-
DROP TABLE IF EXISTS "profile_table";
DROP TABLE IF EXISTS "books_table";
CREATE TABLE IF NOT EXISTS "profile_table" ( "id" INTEGER, "profile_name" TEXT, PRIMARY KEY("id") );
CREATE TABLE "books_table" ( "book_id" INTEGER, "book_name" TEXT, "all" INTEGER, "profile_id" INTEGER, PRIMARY KEY("book_id" AUTOINCREMENT) );
/* Generate some data 100 profiles and 10000 books*/
WITH loop(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM loop LIMIT 100)
INSERT INTO profile_table (profile_name) SELECT 'Profile'||x FROM loop;
WITH loop(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM loop LIMIT 10000)
INSERT INTO books_table (book_name,`all`,profile_id) SELECT 'Book'||x,abs(random() % 10),(abs(random()) % (SELECT max(id) FROM profile_table)) + 1 FROM loop;
/* Display the data */
SELECT * FROM books_table JOIN profile_table ON profile_id=id ORDER BY CAST(substr(profile_name,8) AS INTEGER);
查询显示数据如:-
- 实际显示了10000行
步骤 2 - 创建资产
资产目录已创建,数据库已复制并粘贴为 student_database.db :-
- 请注意,这是为了重新运行能力
制作的副本
步骤 3 添加 createFromAsset
和对 运行 初始测试的其他更改
MyRoomDatabase class 已更改为添加 .createFromAsset
:-
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
MyRoomDatabase.class, "student_prepare_room_database")
.createFromAsset("student_database.db") //<<<<< STEP 3 - ADDED
.addCallback(sRoomDatabaseCallback) //<<<< added for convenience/brevity
.allowMainThreadQueries()
.build();
}
另外 BookDAO 通过添加进行了修改:-
@Query("SELECT * FROM books_table")
List<Book> getAllBooks();
- 允许简单访问数据库(除非访问数据库不会打开检查等)。
最后 MainActivity 被编码为:-
public class MainActivity extends AppCompatActivity {
MyRoomDatabase db;
BookDAO bookDAO;
ProfileDAO profileDAO;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = MyRoomDatabase.getDatabase(this);
bookDAO = db.bookDao();
profileDAO = db.profileDAO();
for (Book b: bookDAO.getAllBooks()) {
Log.d("BOOKINFO","Book is " + b.getName());
}
}
}
第 4 步房间 SQL
项目随后被编译(getters/setters 添加)createALLTables 为:-
- 注意配置文件上的 AUTOINCREMENT table。
步骤 5 运行(见注释)
- 注意这一步纯粹是为了演示如果数据库没有改变会发生什么。
综上所述,如果应用程序是 运行(不是应该的,因为它会失败)。正如预期的那样,它因 Expected/Found 不匹配问题而失败,但很明显它复制了资产:-
2022-01-05 07:59:02.200 1941-1941/? D/AndroidRuntime: Shutting down VM
2022-01-05 07:59:02.202 1941-1941/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: a.a.so70580333prepackageddatabase, PID: 1941
java.lang.RuntimeException: Unable to start activity ComponentInfo{a.a.so70580333prepackageddatabase/a.a.so70580333prepackageddatabase.MainActivity}: java.lang.IllegalStateException: Pre-packaged database has an invalid schema: books_table(a.a.so70580333prepackageddatabase.Book).
Expected:
TableInfo{name='books_table', columns={all=Column{name='all', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, book_id=Column{name='book_id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null'}, book_name=Column{name='book_name', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, profile_id=Column{name='profile_id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='books_table', columns={all=Column{name='all', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, profile_id=Column{name='profile_id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, book_id=Column{name='book_id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}, book_name=Column{name='book_name', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
STEP 6 修改预打包数据库
重新访问第 3 方工具并使用以下内容:-
DROP TABLE IF EXISTS books_table_original;
DROP TABLE IF EXISTS profile_table_original;
ALTER TABLE books_table RENAME TO books_table_original;
ALTER TABLE profile_table RENAME TO profile_table_original;
/* COPIED FROM createAllTables method */
CREATE TABLE IF NOT EXISTS `books_table` (`book_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `book_name` TEXT, `all` INTEGER NOT NULL, `profile_id` INTEGER NOT NULL);
CREATE TABLE IF NOT EXISTS `profiles_table` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `profile_name` TEXT);
INSERT INTO profiles_table SELECT * FROM profile_table_original;
INSERT INTO books_table SELECT * FROM books_table_original;
/* CLEANUP */
DROP TABLE IF EXISTS books_table_original;
DROP TABLE IF EXISTS profile_table_original;
VACUUM;
请注意 expected/found 问题甚至都没有被关注
- 如果查看它们,您会发现 All 列应该为 NOT NULL,但它发现 All 列没有定义,因此允许 NULLS(不匹配)。
- 同样适用于 book_id 列(另一个不匹配)
- 同样适用于 profile_id 列(另一个不匹配)
- 如果这些是固定的,那么 profiles_table 将导致更多不匹配,因为 table 名称不同(altered/corrected 在以上)。
请注意,如果引入了外键约束,那么删除 table 的顺序与创建它们的顺序一样重要(但我相信空间排序 tables)。
以上假设预打包数据库中的table列顺序与Room构建的SQL中的列顺序相同。如果顺序不同,则可以将 INSERT 修改为:-
指定要按选择顺序插入的列,例如INSERT INTO profiles_table (id,profile_name) SELECT * FROM profile_table_original
根据定义的顺序指定 SELECT 列,例如INSERT INTO profiles_table SELECT (
id,
profile_name) FROM profile_table_original
为 INSERT 和 SELECT 指定列而不是 *,例如INSERT INTO profiles_table (profile_name,id) SELECT (profile_name,id) FROM profile_table_original
- 请注意,最后一个示例有意使用不同的列顺序来演示不同的顺序。它不会影响 table 中列的顺序,只会影响 SQLite.
中构建的中间输出中列的顺序
运行完成上述操作后,数据库被保存并复制到资产文件夹。
- 在这种情况下,数据库最初被粘贴为 AlteredFroRoom_student_database.db,student_database.db 屁股被删除,然后 AlterForRoom_student_database.db 被复制并粘贴为 student_database.db。 注意 对于要分发的应用程序,您不希望拥有额外的数据库副本,因为这会增加分发的大小。
然后卸载该应用程序,然后重新运行并成功运行。
- 请注意,由于已复制数据库,不会调用 onCreate 回调(会调用 onOpen)。
日志包括:-
2022-01-05 08:56:15.975 D/BOOKINFO: Book is Book1
2022-01-05 08:56:15.975 D/BOOKINFO: Book is Book2
2022-01-05 08:56:15.975 D/BOOKINFO: Book is Book3
2022-01-05 08:56:15.975 D/BOOKINFO: Book is Book4
2022-01-05 08:56:15.975 D/BOOKINFO: Book is Book5
2022-01-05 08:56:15.975 D/BOOKINFO: Book is Book6
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book7
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book8
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book9
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book10
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book11
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book12
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book13
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book14
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book15
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book16
....
我有一个处理外部数据库(sqlite数据库文件)的项目,我想移动到房间数据库如下
- 数据库 (student_database.db) 的内容最初由第三方应用程序输入,例如(DB Browser for SQLite)。
- 当我 运行 我的应用程序创建了数据库空间并将数据从 student_database.db 3 我的应用程序在 Recycler View 中显示来自 (room db) 的数据
- 新数据可以添加到数据库(房间)
这是我项目的一些文件
@Entity(tableName = "books_table")
public class Book {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "book_id")
private long id;
@ColumnInfo(name = "book_name")
private String name;
@ColumnInfo(name = "all")
private long all;
@ColumnInfo(name = "profile_id")
private long profileId;
public Book() {
}
public Book(String name, long all, long profileId) {
this.name = name;
this.all = all;
this.profileId = profileId;
}
@Dao
public interface BookDAO {
@Insert
void insertBook(Book... book);
@Update
void updateBook(Book... book);
@Entity (tableName = "profiles_table")
public class Profile {
@PrimaryKey(autoGenerate = true)
long id;
@ColumnInfo (name = "profile_name")
String profileName;
public Profile() {
}
public Profile(long id, String profileName) {
this.id = id;
this.profileName = profileName;
}
public Profile(String profileName) {
this.profileName = profileName;
}
@Dao
public interface ProfileDAO {
@Insert
void insertProfile(Profile... profile);
@Update
void updateProfile(Profile... profile);
@Database(entities = {Book.class , Profile.class}, version = 1, exportSchema = false)
public abstract class MyRoomDatabase extends RoomDatabase {
public abstract BookDAO bookDao();
public abstract ProfileDAO profileDAO();
private static volatile MyRoomDatabase INSTANCE;
private static final int NUMBER_OF_THREADS = 4;
static final ExecutorService databaseWriteExecutor =
Executors.newFixedThreadPool(NUMBER_OF_THREADS);
static MyRoomDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
synchronized (MyRoomDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
MyRoomDatabase.class, "student_prepare_room_database")
.addCallback(sRoomDatabaseCallback)
.build();
}
}
}
return INSTANCE;
}
private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
// If you want to keep data through app restarts,
// comment out the following block
databaseWriteExecutor.execute(() -> {
// Populate the database in the background.
// If you want to start with more words, just add them.
});
}
};
}
student_database.db
CREATE TABLE "profile_table" ("id" INTEGER,"profile_name" TEXT,PRIMARY KEY("id"));
[1]: https://i.stack.imgur.com/lDhtR.png
CREATE TABLE "books_table" ("book_id" INTEGER,"book_name" TEXT,"all" INTEGER,"profile_id" INTEGER,PRIMARY KEY("book_id" AUTOINCREMENT));
[2]: https://i.stack.imgur.com/NiuZe.png
通常,这将通过使外部数据库成为资产(预打包的数据库)并利用 .createFromAsset
来进行,后者将进行数据库的复制。
但是,使用上面的 REQUIRE 资产数据库严格符合由 classes 定义的房间模式 @Entity
并包含在通过 @Database
注释提供的实体 list/array 中。
可以使用prePackagedDatabaseCallback
修改预打包的数据库来适配。但是,对外部数据库进行更改以使其符合房间的预期可能更简单。
在您的情况下,例如,您在 配置文件 table 中不匹配,因为在 external/pre-packaged 数据库中您有 id 作为(有效地)INTEGER PRIMARY KEY
而通过使用 @PrimaryKey(autoGenerate = true)
房间期望 INTEGER PRIMARY KEY AUTOINCREMENT
.
AUTOINCREMENT
(在房间autogenerate = true
中)效率低下且很少需要。您可以改为使用@PrimaryKey
.
让房间变得简单
只讨论了一个不匹配的例子,因为很可能没有必要深入研究所有会导致问题的不匹配。当用 @Entity
注释的 classes 已经创建并包含在 classes 的列表中时,当您编译项目时,空间将生成预期的 CREATE TABLE ....
语句@Database
注释。因此,您可以根据 room.
Room创建的SQL在java(generated)中找到(在Android View)m,要查找的 class 与 class 同名,注释为 @Database
但后缀为 _Impl。 SQL 在名为 createAllTables
的方法中找到。您不想创建 room_master_table,它是一个 table,room 用于存储模式的哈希表示,并用于检查是否已对模式进行更改。
演示
根据您的问题使用 code/schemas(进行一些细微的更改以简化演示)。
第 1 步 - 根据您的模式预打包数据库
- 显然你有这个
首先,根据您的 SQL 创建了一个数据库,并在第三方工具 (Navicat) 中填充了大约 100 个配置文件和 10000 本书:-
DROP TABLE IF EXISTS "profile_table";
DROP TABLE IF EXISTS "books_table";
CREATE TABLE IF NOT EXISTS "profile_table" ( "id" INTEGER, "profile_name" TEXT, PRIMARY KEY("id") );
CREATE TABLE "books_table" ( "book_id" INTEGER, "book_name" TEXT, "all" INTEGER, "profile_id" INTEGER, PRIMARY KEY("book_id" AUTOINCREMENT) );
/* Generate some data 100 profiles and 10000 books*/
WITH loop(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM loop LIMIT 100)
INSERT INTO profile_table (profile_name) SELECT 'Profile'||x FROM loop;
WITH loop(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM loop LIMIT 10000)
INSERT INTO books_table (book_name,`all`,profile_id) SELECT 'Book'||x,abs(random() % 10),(abs(random()) % (SELECT max(id) FROM profile_table)) + 1 FROM loop;
/* Display the data */
SELECT * FROM books_table JOIN profile_table ON profile_id=id ORDER BY CAST(substr(profile_name,8) AS INTEGER);
查询显示数据如:-
- 实际显示了10000行
步骤 2 - 创建资产 资产目录已创建,数据库已复制并粘贴为 student_database.db :-
- 请注意,这是为了重新运行能力 制作的副本
步骤 3 添加 createFromAsset
和对 运行 初始测试的其他更改
MyRoomDatabase class 已更改为添加 .createFromAsset
:-
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
MyRoomDatabase.class, "student_prepare_room_database")
.createFromAsset("student_database.db") //<<<<< STEP 3 - ADDED
.addCallback(sRoomDatabaseCallback) //<<<< added for convenience/brevity
.allowMainThreadQueries()
.build();
}
另外 BookDAO 通过添加进行了修改:-
@Query("SELECT * FROM books_table")
List<Book> getAllBooks();
- 允许简单访问数据库(除非访问数据库不会打开检查等)。
最后 MainActivity 被编码为:-
public class MainActivity extends AppCompatActivity {
MyRoomDatabase db;
BookDAO bookDAO;
ProfileDAO profileDAO;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = MyRoomDatabase.getDatabase(this);
bookDAO = db.bookDao();
profileDAO = db.profileDAO();
for (Book b: bookDAO.getAllBooks()) {
Log.d("BOOKINFO","Book is " + b.getName());
}
}
}
第 4 步房间 SQL
项目随后被编译(getters/setters 添加)createALLTables 为:-
- 注意配置文件上的 AUTOINCREMENT table。
步骤 5 运行(见注释)
- 注意这一步纯粹是为了演示如果数据库没有改变会发生什么。
综上所述,如果应用程序是 运行(不是应该的,因为它会失败)。正如预期的那样,它因 Expected/Found 不匹配问题而失败,但很明显它复制了资产:-
2022-01-05 07:59:02.200 1941-1941/? D/AndroidRuntime: Shutting down VM
2022-01-05 07:59:02.202 1941-1941/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: a.a.so70580333prepackageddatabase, PID: 1941
java.lang.RuntimeException: Unable to start activity ComponentInfo{a.a.so70580333prepackageddatabase/a.a.so70580333prepackageddatabase.MainActivity}: java.lang.IllegalStateException: Pre-packaged database has an invalid schema: books_table(a.a.so70580333prepackageddatabase.Book).
Expected:
TableInfo{name='books_table', columns={all=Column{name='all', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, book_id=Column{name='book_id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null'}, book_name=Column{name='book_name', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, profile_id=Column{name='profile_id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='books_table', columns={all=Column{name='all', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, profile_id=Column{name='profile_id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, book_id=Column{name='book_id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}, book_name=Column{name='book_name', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
STEP 6 修改预打包数据库
重新访问第 3 方工具并使用以下内容:-
DROP TABLE IF EXISTS books_table_original;
DROP TABLE IF EXISTS profile_table_original;
ALTER TABLE books_table RENAME TO books_table_original;
ALTER TABLE profile_table RENAME TO profile_table_original;
/* COPIED FROM createAllTables method */
CREATE TABLE IF NOT EXISTS `books_table` (`book_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `book_name` TEXT, `all` INTEGER NOT NULL, `profile_id` INTEGER NOT NULL);
CREATE TABLE IF NOT EXISTS `profiles_table` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `profile_name` TEXT);
INSERT INTO profiles_table SELECT * FROM profile_table_original;
INSERT INTO books_table SELECT * FROM books_table_original;
/* CLEANUP */
DROP TABLE IF EXISTS books_table_original;
DROP TABLE IF EXISTS profile_table_original;
VACUUM;
请注意 expected/found 问题甚至都没有被关注
- 如果查看它们,您会发现 All 列应该为 NOT NULL,但它发现 All 列没有定义,因此允许 NULLS(不匹配)。
- 同样适用于 book_id 列(另一个不匹配)
- 同样适用于 profile_id 列(另一个不匹配)
- 如果这些是固定的,那么 profiles_table 将导致更多不匹配,因为 table 名称不同(altered/corrected 在以上)。
请注意,如果引入了外键约束,那么删除 table 的顺序与创建它们的顺序一样重要(但我相信空间排序 tables)。
以上假设预打包数据库中的table列顺序与Room构建的SQL中的列顺序相同。如果顺序不同,则可以将 INSERT 修改为:-
指定要按选择顺序插入的列,例如
INSERT INTO profiles_table (id,profile_name) SELECT * FROM profile_table_original
根据定义的顺序指定 SELECT 列,例如
INSERT INTO profiles_table SELECT (
id,
profile_name) FROM profile_table_original
为 INSERT 和 SELECT 指定列而不是 *,例如
INSERT INTO profiles_table (profile_name,id) SELECT (profile_name,id) FROM profile_table_original
- 请注意,最后一个示例有意使用不同的列顺序来演示不同的顺序。它不会影响 table 中列的顺序,只会影响 SQLite. 中构建的中间输出中列的顺序
运行完成上述操作后,数据库被保存并复制到资产文件夹。
- 在这种情况下,数据库最初被粘贴为 AlteredFroRoom_student_database.db,student_database.db 屁股被删除,然后 AlterForRoom_student_database.db 被复制并粘贴为 student_database.db。 注意 对于要分发的应用程序,您不希望拥有额外的数据库副本,因为这会增加分发的大小。
然后卸载该应用程序,然后重新运行并成功运行。
- 请注意,由于已复制数据库,不会调用 onCreate 回调(会调用 onOpen)。
日志包括:-
2022-01-05 08:56:15.975 D/BOOKINFO: Book is Book1
2022-01-05 08:56:15.975 D/BOOKINFO: Book is Book2
2022-01-05 08:56:15.975 D/BOOKINFO: Book is Book3
2022-01-05 08:56:15.975 D/BOOKINFO: Book is Book4
2022-01-05 08:56:15.975 D/BOOKINFO: Book is Book5
2022-01-05 08:56:15.975 D/BOOKINFO: Book is Book6
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book7
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book8
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book9
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book10
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book11
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book12
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book13
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book14
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book15
2022-01-05 08:56:15.976 D/BOOKINFO: Book is Book16
....