我正在基于一个旧的Android项目构建一个Android应用程序。 在我的新应用程序中,我正在使用Room。我必须使用第一个项目中使用的相同数据库。 此外,我已经使用com.amitshekhar.android:debug-db库从第一个项目中提取了数据库。 获取数据库文件后,我想在Room中打开它。
我正在建立这样的数据库:
Room.databaseBuilder(
androidContext(),
Database::class.java, "database.db"
).createFromAsset("database.db")
.build()
当前我正在使用此createFromAsset()方法,尽管稍后我将使用createFromFile()方法,因为应该从服务器下载数据库。
但是我得到了java.lang.IllegalStateException:预打包的数据库具有无效的架构 之所以会发生这种情况,是因为数据库中存在Room不支持的几种数据类型,例如NVARCHAR(200),DATE或bit。
我知道Room仅使用5种Sql类型,但我不知道如何更改它,以便Room可以使用上述方法打开这种数据库。
问题是如何将NVARCHAR(200),DATE或bit转换为Room支持的数据类型?
答案 0 :(得分:0)
您必须将数据库转换为使用Room支持并与实体匹配的特定列类型关联。
对于 NVARCHAR(200),您需要 TEXT 将NVARCHAR(200)替换为将列定义为字符串的实体。
对于 DATE ,如果您使用的是基于字符串的日期,则取决于Entity定义。 YYYY-MM-DD hh:mm:ss,则“实体”应为String,列亲和力为 TEXT 。如果将日期存储为时间戳,则实体应为长且列亲和性 INTEGER 。
答案在这里 Can't migrate a table to Room do to an error with the way booleans are saved in Sqlite进行了一次转换,将BOOL的值更改为INTEGER。
您可以对此进行调整(尽管我会对DATE保持谨慎)以适应。
您可能会发现以下有用。您可以在喜爱的SQLite Manager工具中针对预先存在的数据库运行它。
WITH potentialRoomChanges AS (
SELECT sm.name AS tablename, pti.name AS columnname, pti.type, dflt_value, pk,
CASE
WHEN instr(upper(pti.type),'INT') THEN 'INTEGER'
WHEN instr(upper(pti.type),'CHAR') OR instr(upper(pti.type),'CLOB') OR instr(upper(pti.type),'TEXT') THEN 'TEXT'
WHEN instr(upper(pti.type),'BLOB') THEN 'BLOB'
WHEN instr(upper(pti.type),'REAL') OR instr(upper(pti.type),'FLOA') OR instr(upper(pti.type),'DOUB') THEN 'REAL'
ELSE 'NUMERIC'
END AS roomtype ,
CASE WHEN pti.[notnull] THEN 'Investigate NOT NULL USE' END AS nnindicator,
sql
FROM sqlite_master AS sm JOIN pragma_table_info(sm.name) AS pti
WHERE
sm.type = 'table'
AND sm.name NOT LIKE 'sqlite_%'
AND sm.name <> 'android_metadata'
AND (
upper(pti.type) <> roomtype
OR instr(roomtype,'NUMERIC')
OR nnindicator IS NOT NULL
OR dflt_value IS NOT NULL
OR pk > 0
)
ORDER BY sm.name,pti.cid
)
SELECT tablename, columnname, type, roomtype,
CASE WHEN upper(type) <> upper(roomtype) THEN 'Investigate TYPE should be ' ||roomtype END AS typechange_notes,
CASE WHEN roomtype = 'NUMERIC' THEN 'Investigate NUMERIC' END AS numeric_notes,
CASE WHEN dflt_value IS NOT NULL THEN 'Investigate DEFAULT VALUE of '||dflt_value END AS default_notes,
CASE WHEN pk > 0 THEN 'Investigate PRIMARY KEY inclusion' END AS primarykey_notes,
nnindicator AS notnull_notes
FROM potentialRoomChanges
;
希望列/文本不言自明。这基于定义的列类型(可能与所使用的类型不同)。例如浮动点(显示第5行),您会认为这是真实的。但是,根据派生的类型相似性,已应用了第一个规则(如果类型包括INT,则为INTEGER)。
根据Datatypes In SQLite Version 3 - 3.1. Determination Of Column Affinity的规则。
根据我有限的房间经验,NUMERIC 并不是它使用的一种类型,因此应始终将其更改为其他类型之一。 / em>
答案 1 :(得分:0)
在Pojo(实体)类的每个字段之前使用@NonNull
。
无需在主键字段中添加@NonNull
。
下面是一个例子
@Entity(tableName = "station")
public class Station {
@PrimaryKey
private int id;
@NonNull
private String name;
@NonNull
private int line;
@NonNull
private double lat;
@NonNull
private double lon;
... constructor, getters and setters
}
答案 2 :(得分:0)
对我来说问题是 Not-Null
,对于数据库中带有 NOT NULL
的每一列,它应该反映在带有 @NonNull
的模型中。
如果你在数据库中LastName
是
"LastName" TEXT NOT NULL,
在您的模型上的代码中,它应该是
@NonNull
private String LastName;