预打包数据库有一个无效的架构错误
Pre-packaged database has an invalid schema error
我正在基于旧的 Android 项目构建 Android 应用程序。
在我的新应用程序中,我使用的是 Room。我必须使用第一个项目中使用的相同数据库。
此外,我使用 com.amitshekhar.android:debug-db 库从第一个项目中提取了数据库。
获取数据库文件后,我想用房间打开它。
我正在这样构建数据库:
Room.databaseBuilder(
androidContext(),
Database::class.java, "database.db"
).createFromAsset("database.db")
.build()
目前我正在使用这个 createFromAsset() 方法,虽然后来我会使用 createFromFile() 方法,因为我的数据库应该从服务器下载。
但我收到 java.lang.IllegalStateException: 预打包数据库的架构无效
发生这种情况是因为数据库中有几种数据类型在 Room 中不受支持,例如 NVARCHAR(200)、DATE 或位。
我知道 Room 只使用五种 Sql 类型,但我不知道如何更改它以便 Room 可以使用上述方法打开这种数据库。
问题是如何将NVARCHAR(200)、DATE或bit转换成Room支持的数据类型?
您必须转换数据库以使用 Room 支持且与实体匹配的特定列类型关联。
对于 NVARCHAR(200),您需要让 TEXT 将 NVARCHAR(200) 替换为将列定义为字符串的实体。
对于 DATE 如果您使用基于字符串的日期,则取决于实体定义,例如YYYY-MM-DD hh:mm:ss 那么 Entity 应该是 String 并且列 affinity TEXT。如果将日期存储为时间戳,则实体应该很长并且列亲和力
整数.
答案在这里
进行转换以将 BOOL 更改为 INTEGER。
您可以对此进行调整(尽管我会对 DATE 持谨慎态度)以适应。
额外
您可能会发现以下内容有用。您 运行 它针对您最喜欢的 SQLite 管理器工具中的 pre-existing 数据库。
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
;
示例输出:-
希望 columns/text 是 self-explanatory。这基于定义的列类型(可能与使用的类型不同)。例如浮点数(显示第 5 行)你会认为是真实的。但是,根据派生类型亲和性,已应用第一条规则(如果类型包括 INT,则为 INTEGER)。
规则根据 Datatypes In SQLite Version 3 - 3.1. Determination Of Column Affinity。
NUMERIC 根据我对房间的有限经验,它不是它使用的类型,因此应始终将其更改为其他类型之一。
在你 Pojo(实体)的每个字段前使用 @NonNull
class。
无需将 @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
}
对我来说问题是 Not-Null
,对于数据库中带有 NOT NULL
的每一列,它应该反映在您带有 @NonNull
.
的模型中
如果你LastName
在数据库中是
"LastName" TEXT NOT NULL,
在您的模型代码中,它应该是
@NonNull
private String LastName;
在我的例子中,通过更改不同于我的数据库名称的 name
参数解决了错误。在此代码中,我将 name
参数设置为 "my_db"
fun getInstance(context: Context): AppDatabase {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(
context,
AppDatabase::class.java,
"my_db" //this parameter
)
.allowMainThreadQueries()
.createFromAsset("database/harry_potter.db")
.build()
}
}
我正在基于旧的 Android 项目构建 Android 应用程序。 在我的新应用程序中,我使用的是 Room。我必须使用第一个项目中使用的相同数据库。 此外,我使用 com.amitshekhar.android:debug-db 库从第一个项目中提取了数据库。 获取数据库文件后,我想用房间打开它。
我正在这样构建数据库:
Room.databaseBuilder(
androidContext(),
Database::class.java, "database.db"
).createFromAsset("database.db")
.build()
目前我正在使用这个 createFromAsset() 方法,虽然后来我会使用 createFromFile() 方法,因为我的数据库应该从服务器下载。
但我收到 java.lang.IllegalStateException: 预打包数据库的架构无效 发生这种情况是因为数据库中有几种数据类型在 Room 中不受支持,例如 NVARCHAR(200)、DATE 或位。
我知道 Room 只使用五种 Sql 类型,但我不知道如何更改它以便 Room 可以使用上述方法打开这种数据库。
问题是如何将NVARCHAR(200)、DATE或bit转换成Room支持的数据类型?
您必须转换数据库以使用 Room 支持且与实体匹配的特定列类型关联。
对于 NVARCHAR(200),您需要让 TEXT 将 NVARCHAR(200) 替换为将列定义为字符串的实体。
对于 DATE 如果您使用基于字符串的日期,则取决于实体定义,例如YYYY-MM-DD hh:mm:ss 那么 Entity 应该是 String 并且列 affinity TEXT。如果将日期存储为时间戳,则实体应该很长并且列亲和力 整数.
答案在这里
您可以对此进行调整(尽管我会对 DATE 持谨慎态度)以适应。
额外
您可能会发现以下内容有用。您 运行 它针对您最喜欢的 SQLite 管理器工具中的 pre-existing 数据库。
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
;
示例输出:-
希望 columns/text 是 self-explanatory。这基于定义的列类型(可能与使用的类型不同)。例如浮点数(显示第 5 行)你会认为是真实的。但是,根据派生类型亲和性,已应用第一条规则(如果类型包括 INT,则为 INTEGER)。
规则根据 Datatypes In SQLite Version 3 - 3.1. Determination Of Column Affinity。
NUMERIC 根据我对房间的有限经验,它不是它使用的类型,因此应始终将其更改为其他类型之一。
在你 Pojo(实体)的每个字段前使用 @NonNull
class。
无需将 @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
}
对我来说问题是 Not-Null
,对于数据库中带有 NOT NULL
的每一列,它应该反映在您带有 @NonNull
.
如果你LastName
在数据库中是
"LastName" TEXT NOT NULL,
在您的模型代码中,它应该是
@NonNull
private String LastName;
在我的例子中,通过更改不同于我的数据库名称的 name
参数解决了错误。在此代码中,我将 name
参数设置为 "my_db"
fun getInstance(context: Context): AppDatabase {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(
context,
AppDatabase::class.java,
"my_db" //this parameter
)
.allowMainThreadQueries()
.createFromAsset("database/harry_potter.db")
.build()
}
}