Android 房间:根据外部输入创建 table
Android Room: Create table based on external input
我正在开发一个基于 Java 的 Android 应用程序,我正在使用 Room。该应用程序连接到服务器,从中下载项目特定配置。这些配置之一是 table 的设置。我有一个 table 每个项目的列数和类型不同。我需要在 phone 上有此 table 的本地副本以存储数据,以防没有可用的互联网连接。 table 的配置包含 table 的名称和列组成 like
[{
"name":"column1",
"datatype":"VARCHAR(20)"
},
{
"name":"column2",
"datatype":"INT(5)"
},
{
"name":"column3",
"datatype":"DOUBLE"
}]
如何使用 Room 生成这样的 table?生成创建查询不是问题,但我应该在哪里执行它。此外,如何从 table 插入、更新和查询数据?是否可以生成这样的 SQL 查询并执行它们?是否有类似行映射器的东西可用于从 table 读取查询数据?
如果这是不可能的,知道我该如何解决吗?
感谢您的支持。
您将无法使用 Room 执行此操作并使用 Room 的对象映射,因为 Room 根据对象映射构建 tables。
- 那是一个table是根据一个用@Entity注解的class定义的,定义为一个实体到数据库。
它在编译时承担很多工作,例如验证构建其组件创建的查询 SQL。在 运行 时,作为打开数据库的一部分,它会检查预期的组件,如果发现差异,将 fail/crash.
我曾经有一个正在进行的项目,该项目基于数据库构建 entities/classes,可以将其复制到项目中,但会更改 Room 并引入功能(例如,忽略但随后引入的 DEFAULT 约束) .
您可以拥有不属于 controlled/known Room 的组件,包括 tables,这不会违反 运行 时间架构检查,但您必须使用支持SQLiteDatabase 所以你不妨使用原生 SQLite.
How can I generate such a table with Room?
在示例的情况下,您需要使用 @Entity 注释的 class。但是,Room 强加的一条规则是必须有一个 PRIMARY KEY。因此,一个选项可能是引入一个。让我们说一个名为 id
的列
Room 强制执行的另一条规则是列类型只能是 INTEGER、TEXT、REAL 或 BLOB。然而这是由变量类型决定的。
- 所以 VARCHAR(50) 将用于字符串,
- INT(5) 可能会存储 long 或 int long 会覆盖所有。
- DOUBLE 可能会存储一个 DOUBLE (REAL) 所以加倍。
所以 class(实体)可以是:-
@Entity
class TableX {
@PrimaryKey
Long id = null;
String column1;
long column2;
double column3;
}
- table 名称将是 TableX
How can I insert, update and query data from the table?
你使用一个接口或抽象 class 注释 @Dao,所以对于上面你可以,例如:-
@Dao
abstract class TableXDao {
@Insert
abstract long insert(TableX tableX);
@Insert
abstract long[] insert(TableX...tableX);
@Query("INSERT INTO TableX (column1,column2,column3) VALUES(:column1,:column2,:column3)")
abstract long insert(String column1,long column2, double column3);
@Update
abstract int update(TableX tableX);
@Update
abstract int update(TableX...tableX);
@Query("UPDATE tablex set column1=:newColumn1, column2=:newColumn2,column3=:newColumn3 WHERE id=:id")
abstract int update(long id, String newColumn1, long newColumn2, double newColumn3);
@Query("SELECT * FROM tablex")
abstract List<TableX> getAllTableXRows();
}
- 注意 Insert/Update 的 3 种形式 @Insert/@Update 使用方便的方法(基于传递一个或多个对象)@Query 使用更多 free-format/adaptable 方法。
虽然没有要求 Room 需要知道数据库本身,所以另一个 class,用 @Database 注释是必需的,这个注释定义了构成数据库的实体,版本号(和其他选项) ). class 应该扩展 RoomDatabase class,它必须是抽象 class 或实现抽象方法 createOpenHelper
(通常是前者)。所以:-
@Database(entities = {TableX.class},version = 1)
abstract class TheDatabase extends RoomDatabase {
abstract TableXDao getTableXDao();
/* Often :- */
private static volatile TheDatabase instance = null;
public TheDatabase getInstance(Context context) {
if (instance == null) {
instance = Room.databaseBuilder(
context,TheDatabase.class,"thedatabase.db"
)
.build();
}
return instance;
}
}
当上面的编译很多时,构建会包含一个警告:-
E:\AndroidStudioApps\SO70351715JavaSQLite\app\src\main\java\a\a\so70351715javasqlite\TheDatabase.java:10: warning: Schema export directory is not provided to the annotation processor so we cannot export the schema. You can either provide `room.schemaLocation` annotation processor argument OR set exportSchema to false.
abstract class TheDatabase extends RoomDatabase {
^
1 warning
- 故意允许发生以演示广泛的编译时检查
此外,它会生成相当多的 java 代码 :-
TableXDao_Impl class是使用Dao时调用的代码
TheDatabase_Impl class 是访问数据库的代码,包括在 createAllTables 方法中创建 tables:-
@Override
public void createAllTables(SupportSQLiteDatabase _db) {
_db.execSQL("CREATE TABLE IF NOT EXISTS `TableX` (`id` INTEGER, `column1` TEXT, `column2` INTEGER NOT NULL, `column3` REAL NOT NULL, PRIMARY KEY(`id`))");
_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, '5f1c580621c8b86aef3b3cccc44d8d76')");
}
如您所见,room_master_table 已创建并填充了存储哈希的行,这是验证的一部分,如果更改了哈希,则 room 将知道架构已更改(源代码已更改)。
Is there something like a row mapper which can be used to read the queried data from the table?
可以看出,这一切都是通过注释通过编译代码完成的,因此没有映射,但期望在编译时一切都是 known/defined。
If this is not possible, any idea how I can solve it otherwise?
Use Native SQLite or manage the server database and the room database as a whole.
我正在开发一个基于 Java 的 Android 应用程序,我正在使用 Room。该应用程序连接到服务器,从中下载项目特定配置。这些配置之一是 table 的设置。我有一个 table 每个项目的列数和类型不同。我需要在 phone 上有此 table 的本地副本以存储数据,以防没有可用的互联网连接。 table 的配置包含 table 的名称和列组成 like
[{
"name":"column1",
"datatype":"VARCHAR(20)"
},
{
"name":"column2",
"datatype":"INT(5)"
},
{
"name":"column3",
"datatype":"DOUBLE"
}]
如何使用 Room 生成这样的 table?生成创建查询不是问题,但我应该在哪里执行它。此外,如何从 table 插入、更新和查询数据?是否可以生成这样的 SQL 查询并执行它们?是否有类似行映射器的东西可用于从 table 读取查询数据? 如果这是不可能的,知道我该如何解决吗? 感谢您的支持。
您将无法使用 Room 执行此操作并使用 Room 的对象映射,因为 Room 根据对象映射构建 tables。
- 那是一个table是根据一个用@Entity注解的class定义的,定义为一个实体到数据库。
它在编译时承担很多工作,例如验证构建其组件创建的查询 SQL。在 运行 时,作为打开数据库的一部分,它会检查预期的组件,如果发现差异,将 fail/crash.
我曾经有一个正在进行的项目,该项目基于数据库构建 entities/classes,可以将其复制到项目中,但会更改 Room 并引入功能(例如,忽略但随后引入的 DEFAULT 约束) .
您可以拥有不属于 controlled/known Room 的组件,包括 tables,这不会违反 运行 时间架构检查,但您必须使用支持SQLiteDatabase 所以你不妨使用原生 SQLite.
How can I generate such a table with Room?
在示例的情况下,您需要使用 @Entity 注释的 class。但是,Room 强加的一条规则是必须有一个 PRIMARY KEY。因此,一个选项可能是引入一个。让我们说一个名为 id
的列Room 强制执行的另一条规则是列类型只能是 INTEGER、TEXT、REAL 或 BLOB。然而这是由变量类型决定的。
- 所以 VARCHAR(50) 将用于字符串,
- INT(5) 可能会存储 long 或 int long 会覆盖所有。
- DOUBLE 可能会存储一个 DOUBLE (REAL) 所以加倍。
所以 class(实体)可以是:-
@Entity
class TableX {
@PrimaryKey
Long id = null;
String column1;
long column2;
double column3;
}
- table 名称将是 TableX
How can I insert, update and query data from the table?
你使用一个接口或抽象 class 注释 @Dao,所以对于上面你可以,例如:-
@Dao
abstract class TableXDao {
@Insert
abstract long insert(TableX tableX);
@Insert
abstract long[] insert(TableX...tableX);
@Query("INSERT INTO TableX (column1,column2,column3) VALUES(:column1,:column2,:column3)")
abstract long insert(String column1,long column2, double column3);
@Update
abstract int update(TableX tableX);
@Update
abstract int update(TableX...tableX);
@Query("UPDATE tablex set column1=:newColumn1, column2=:newColumn2,column3=:newColumn3 WHERE id=:id")
abstract int update(long id, String newColumn1, long newColumn2, double newColumn3);
@Query("SELECT * FROM tablex")
abstract List<TableX> getAllTableXRows();
}
- 注意 Insert/Update 的 3 种形式 @Insert/@Update 使用方便的方法(基于传递一个或多个对象)@Query 使用更多 free-format/adaptable 方法。
虽然没有要求 Room 需要知道数据库本身,所以另一个 class,用 @Database 注释是必需的,这个注释定义了构成数据库的实体,版本号(和其他选项) ). class 应该扩展 RoomDatabase class,它必须是抽象 class 或实现抽象方法 createOpenHelper
(通常是前者)。所以:-
@Database(entities = {TableX.class},version = 1)
abstract class TheDatabase extends RoomDatabase {
abstract TableXDao getTableXDao();
/* Often :- */
private static volatile TheDatabase instance = null;
public TheDatabase getInstance(Context context) {
if (instance == null) {
instance = Room.databaseBuilder(
context,TheDatabase.class,"thedatabase.db"
)
.build();
}
return instance;
}
}
当上面的编译很多时,构建会包含一个警告:-
E:\AndroidStudioApps\SO70351715JavaSQLite\app\src\main\java\a\a\so70351715javasqlite\TheDatabase.java:10: warning: Schema export directory is not provided to the annotation processor so we cannot export the schema. You can either provide `room.schemaLocation` annotation processor argument OR set exportSchema to false.
abstract class TheDatabase extends RoomDatabase {
^
1 warning
- 故意允许发生以演示广泛的编译时检查
此外,它会生成相当多的 java 代码 :-
TableXDao_Impl class是使用Dao时调用的代码 TheDatabase_Impl class 是访问数据库的代码,包括在 createAllTables 方法中创建 tables:-
@Override
public void createAllTables(SupportSQLiteDatabase _db) {
_db.execSQL("CREATE TABLE IF NOT EXISTS `TableX` (`id` INTEGER, `column1` TEXT, `column2` INTEGER NOT NULL, `column3` REAL NOT NULL, PRIMARY KEY(`id`))");
_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, '5f1c580621c8b86aef3b3cccc44d8d76')");
}
如您所见,room_master_table 已创建并填充了存储哈希的行,这是验证的一部分,如果更改了哈希,则 room 将知道架构已更改(源代码已更改)。
Is there something like a row mapper which can be used to read the queried data from the table?
可以看出,这一切都是通过注释通过编译代码完成的,因此没有映射,但期望在编译时一切都是 known/defined。
If this is not possible, any idea how I can solve it otherwise? Use Native SQLite or manage the server database and the room database as a whole.