将数据类型从SQLite转储文件Map到Room实体

slwdgvem  于 2023-05-07  发布在  SQLite
关注(0)|答案(1)|浏览(206)

我有一个db.sqlite转储文件。当我在SQLite Browser中查看它时,我可以看到它包含许多CREATE TABLE, CREATE INDEX语句。我使用这个转储文件通过createFromAsset("db.sqlite")函数创建我的房间数据库。
我的问题是,将这些表中的数据类型从转储文件Map到Room实体中的Kotlin数据类型的正确方法是什么?从SQLite转储文件到Room实体的数据类型Map是否有规则?有没有一个自动化的工具/库可以为我做这件事?
SQLite Browser在这些表中显示的类型非常广泛:

date, datetime, mediumtext, varchar(255), varchar(32), tinyint(1), int(1), int(10), bigint(20), TEXT
5uzkadbs

5uzkadbs1#

有没有一个自动化的工具/库可以为我做这件事?

(我知道)。我确实有一个,但随着房间开始改变/增加功能,它成为一个噩梦,它并不是很难转换。如下文所示,Room可以帮助您并使您的生活更轻松。

我的问题是,将这些表中的数据类型从转储文件Map到Room实体中的Kotlin数据类型的正确方法是什么?从SQLite转储文件到Room实体的数据类型Map是否有规则?
列类型为INTEGER、TEXT、BLOB或真实的四种类型之一。只能使用这些类型。但是,当Room查看@Entity注解类中的字段时,Room将根据类型生成这些字段。

*房间不符合默认/通过NUMERIC类型下降,它不能使用,必须转换。

1.字符串将转换为TEXT
1.整数类型(例如LongIntByte....)将转换为INTEGER
1.十进制类型(例如DoubleFloat....)将转换为真实的
1.一个字节流,例如ByteArray,将被转换为BLOB
1.更复杂的对象(例如,Date)必须转换为基本类型或String(通常后者作为JSON表示),或者可以添加组成对象的字段(可能通过@Embedded注解)
1.通过基本的原始类型,这并不意味着按照Java int,long等实际的原始类型,而是Room知道的类型将是上面四种列类型之一。
现在考虑date, datetime, mediumtext, varchar(255), varchar(32), tinyint(1), int(1), int(10), bigint(20), TEXT

  • 日期,你需要看看日期值是如何存储的,它是一个文本表示,例如。2023-01-01还是一个整数值?字段类型分别为StringLong
  • 如果使用Date类型对象,例如var mydate: Date然后你需要一个TypeConverter将日期转换为Long/Int或String(如果需要,甚至是ByteArray)。
  • 日期时间也一样。
  • mediumtext,可能为String
  • varchar很可能是String
  • 所有其他的都很可能是LongInt
  • 注意。除了定义为INTEGER的列是PRIMARY KEY的唯一列之外,SQLite可以在任何列中存储任何类型但ROOM不会

现在,您可能遇到的真实的问题是,如果使用createFromAsset,您将需要转换资产。
最简单的方法是首先创建@Entity注解的类,每个表一个,基于上面的内容,即决定实际存储什么类型的数据,因为SQLite中的列名非常灵活,而且您可以在任何列中存储任何类型(上面的例外),因此实际数据可能很重要。

当您对建议的实体进行编码时,然后用entities参数指定@Entity注解的类来编码@Database注解的类。它可以像这样简单,例如:

@Database(entities = [Entity1::class,Entity2::class], exportSchema = false, version = 1)
abstract class TheDatabase: RoomDatabase() {
}
    • 显然,@Entity注解的类可能不是EntityEntity2 *

现在编译项目(成功)。
然后,Room将生成包含用于创建表的SQL的java。

上面的示例(基于对各种类型的假设近似):-

Entity1 for want of better names:-

@Entity
data class Entity1(
    @PrimaryKey /* All entities MUST have a primary key */
    var datetime: Long=System.currentTimeMillis(), /* possible use */
    var date: String,
    var mediumtext: String,
    var varchar255: String?, /*<<<<<<<< nullable to demonstrate */
    var varchar32: String,
    var tinyint1: Short,
    var int1: Int,
    var int10: Int,
    var bigint20: Long /* Note BigInteger would need a type converter */
)

@Database注解类:-

@Database(entities = [Entity1::class], exportSchema = false, version = 1)
abstract class TheDatabase: RoomDatabase() {
}

编译成功

例如:-

BUILD SUCCESSFUL in 7s
34 actionable tasks: 8 executed, 26 up-to-date

在Android View中,
1.找到java(generated),然后
1.与@Database注解类同名的类,后缀为Impl,然后
1.方法名createAllTables
例如:-

从上面的createAllTables方法是:

public void createAllTables(@NonNull final SupportSQLiteDatabase db) {
    db.execSQL("CREATE TABLE IF NOT EXISTS `Entity1` (`datetime` INTEGER NOT NULL, `date` TEXT NOT NULL, `mediumtext` TEXT NOT NULL, `varchar255` TEXT, `varchar32` TEXT NOT NULL, `tinyint1` INTEGER NOT NULL, `int1` INTEGER NOT NULL, `int10` INTEGER NOT NULL, `bigint20` INTEGER NOT NULL, PRIMARY KEY(`datetime`))");
    db.execSQL("CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)");
    db.execSQL("INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '142451a6629652e0eafe63b6637a32ff')");
  }

可以看出,Room转换类型如上所述但是注意,Room做了更多的事情,例如添加NOT NULL约束,或者不像varchar255列那样。

  • NOT NULL约束必须符合预期,另外DEFAULT值必须符合预期(即例如,如果使用@ColumnInfo(defaultValue = "whaetever"),则将使用DEFAULT 'whaetever'
  • 如果您需要转换数据,并且没有指定默认值,则资产中的相应列定义必须不具有DEFAULT ....,这可能会使数据的复制复杂化(下面的步骤3)。

Room将只接受具有根据生成的SQL定义的数据库。如果存在任何差异,则结果将是一个例外,即列出房间预期发现
因此,毫无疑问,从资产复制的数据库需要更改(列表中唯一可接受的列类型是TEXT,其他任何列类型都会导致异常)。
您可以在将数据库复制到assets文件夹之前对其进行转换,也可以使用PrepackagedDatabaseCallback,其使用示例可以在此处找到How do I use Room's prepackagedDatabaseCallback?
我相信使用SQLiteBrowser这样的工具更容易,在这种情况下,您可以基于以下转换:
1.使用ALTER TABLE重命名原始表。
1.使用上面获得的生成的SQL创建表。
1.不需要麻烦room_master_table,room会处理。

1.将重命名的原始表中的数据复制到它们的等效表中
1.可以像INSERT INTO entity1 SELECT * FROM renamed_entity1一样简单,也可以更复杂,例如如果NOT NULL的值为null(可能会将?添加到字段中,重新编译等)
1.使用DROP TABLE ....删除重命名的表
1.也许可以考虑做一个VACUUM
1.保存数据库,然后将其复制到assets文件夹中
1.然后可以完成Room代码(添加@Dao注解的接口,修改@Database注解的类,根据需要添加POJO)。如果一切都做得很好,那么数据库应该被打开并成功使用。

相关问题