使用 Room Persistence 在运行时生成查询
Generating a query at runtime using Room Persistance
我想 运行 查询在 运行 时生成的 SQLite 数据库(而不是 @Dao 中的标准编译时查询)。例如,我可能想在 SQLite 数据库中搜索 TEXT 列,以查看它是否包含 N 长度列表中的所有单词。在原始 SQLITE 中,N 为 3 的查询如下所示:
SELECT * FROM table
WHERE textValue LIKE %queryTerm1%
AND textValue LIKE %queryTerm2%"
AND textValue LIKE %queryTerm3%"
我试过生成并传递查询的结尾,而不是仅仅传递变量。例如:
String generatedQuery = "textValue LIKE %queryTerm1% AND textValue LIKE %queryTerm2% AND textValue LIKE %queryTerm3%";
tableDao.find(generatedQuery);
在@Dao 中:
@Query("SELECT * FROM tableName WHERE :endQuery")
List<POJO> find(String endQuery);
这似乎对我不起作用。您知道如何让 运行 时间生成的查询与 Room 一起使用吗?
PS:
我调试了Dao实现,看了一下语句是运行ning。这确认生成的查询信息和查询正在正确传递。我认为这是 SQL 注入预防的问题(也就是 SQLITE 问题,而不是 Room 问题)
问题是您想传递 SQL 语句的一部分,但 Room 将其视为查询参数。
如果你愿意,你可以尝试使用 Kripton Persistence Library,这是一个开源库(由我 :) 编写),它大大简化了 SQLite 对 Android 平台和支持情况的管理代码,例如这个。
Kripton 也使用 DAO 模式,因此概念非常相似。只是写一个适合您需要的例子:
给定一个模型 class:
@BindType
public class User {
public long id;
public String name;
public String username;
public String email;
public Address address;
public String phone;
public String website;
public Company company;
}
一个 DAO 定义:
@BindDao(User.class)
public interface UserDao {
@BindSqlInsert
void insert(User bean);
@BindSqlSelect
List<User> selectDynamic(@BindSqlDynamicWhere String where, @BindSqlDynamicWhereParams String[] args);
}
和数据源定义:
@BindDataSource(daoSet={UserDao.class}, fileName = "kripton.quickstart.db", generateAsyncTask = true)
public interface QuickStartDataSource {
}
Kripton 会在编译时生成所有需要与数据库打交道的代码。因此,要使用 Kripton 完成您的任务,您必须编写类似于以下的代码:
BindQuickStartDataSource ds = BindQuickStartDataSource.instance();
// execute operation in a transaction
ds.execute(new BindQuickStartDataSource.SimpleTransaction() {
@Override
public boolean onExecute(BindQuickStartDaoFactory daoFactory) throws Throwable
{
UserDaoImpl dao = daoFactory.getUserDao();
String[] p={"hello"};
dao.selectDynamic("name=?",p);
return true;
}
});
在logcat中执行上面的代码时你会看到生成的日志:
database OPEN READ_AND_WRITE_OPENED (connections: 1)
UserDaoImpl, selectDynamic (line 352): SELECT id, name, username, email, address, phone, website, company FROM user WHERE name=?
selectDynamic (line 357): ==> param0: 'hello'
Rows found: 0
database CLOSED (READ_AND_WRITE_OPENED) (connections: 0)
Kripton 显然也支持 static where 条件和许多其他功能(我在 2015 年开始开发它)。
有关 Kripton 持久性库的更多信息:
更新:Room 的最新版本 1.1.1 现在使用 SupportSQLiteQuery 而不是 String。
A query with typed bindings. It is better to use this API instead of
rawQuery(String, String[]) because it allows binding type safe
parameters.
新答案:
@Dao
interface RawDao {
@RawQuery(observedEntities = User.class)
LiveData<List<User>> getUsers(SupportSQLiteQuery query);
}
用法:
LiveData<List<User>> liveUsers = rawDao.getUsers( new
SimpleSQLiteQuery("SELECT * FROM User ORDER BY name DESC"));
将您的 gradle 更新为 1.1.1(或任何当前版本)
implementation 'android.arch.persistence.room:runtime:1.1.1'
implementation 'android.arch.lifecycle:extensions:1.1.1'
annotationProcessor "android.arch.persistence.room:compiler:1.1.1"
我想 运行 查询在 运行 时生成的 SQLite 数据库(而不是 @Dao 中的标准编译时查询)。例如,我可能想在 SQLite 数据库中搜索 TEXT 列,以查看它是否包含 N 长度列表中的所有单词。在原始 SQLITE 中,N 为 3 的查询如下所示:
SELECT * FROM table
WHERE textValue LIKE %queryTerm1%
AND textValue LIKE %queryTerm2%"
AND textValue LIKE %queryTerm3%"
我试过生成并传递查询的结尾,而不是仅仅传递变量。例如:
String generatedQuery = "textValue LIKE %queryTerm1% AND textValue LIKE %queryTerm2% AND textValue LIKE %queryTerm3%";
tableDao.find(generatedQuery);
在@Dao 中:
@Query("SELECT * FROM tableName WHERE :endQuery")
List<POJO> find(String endQuery);
这似乎对我不起作用。您知道如何让 运行 时间生成的查询与 Room 一起使用吗?
PS:
我调试了Dao实现,看了一下语句是运行ning。这确认生成的查询信息和查询正在正确传递。我认为这是 SQL 注入预防的问题(也就是 SQLITE 问题,而不是 Room 问题)
问题是您想传递 SQL 语句的一部分,但 Room 将其视为查询参数。
如果你愿意,你可以尝试使用 Kripton Persistence Library,这是一个开源库(由我 :) 编写),它大大简化了 SQLite 对 Android 平台和支持情况的管理代码,例如这个。
Kripton 也使用 DAO 模式,因此概念非常相似。只是写一个适合您需要的例子:
给定一个模型 class:
@BindType
public class User {
public long id;
public String name;
public String username;
public String email;
public Address address;
public String phone;
public String website;
public Company company;
}
一个 DAO 定义:
@BindDao(User.class)
public interface UserDao {
@BindSqlInsert
void insert(User bean);
@BindSqlSelect
List<User> selectDynamic(@BindSqlDynamicWhere String where, @BindSqlDynamicWhereParams String[] args);
}
和数据源定义:
@BindDataSource(daoSet={UserDao.class}, fileName = "kripton.quickstart.db", generateAsyncTask = true)
public interface QuickStartDataSource {
}
Kripton 会在编译时生成所有需要与数据库打交道的代码。因此,要使用 Kripton 完成您的任务,您必须编写类似于以下的代码:
BindQuickStartDataSource ds = BindQuickStartDataSource.instance();
// execute operation in a transaction
ds.execute(new BindQuickStartDataSource.SimpleTransaction() {
@Override
public boolean onExecute(BindQuickStartDaoFactory daoFactory) throws Throwable
{
UserDaoImpl dao = daoFactory.getUserDao();
String[] p={"hello"};
dao.selectDynamic("name=?",p);
return true;
}
});
在logcat中执行上面的代码时你会看到生成的日志:
database OPEN READ_AND_WRITE_OPENED (connections: 1)
UserDaoImpl, selectDynamic (line 352): SELECT id, name, username, email, address, phone, website, company FROM user WHERE name=?
selectDynamic (line 357): ==> param0: 'hello'
Rows found: 0
database CLOSED (READ_AND_WRITE_OPENED) (connections: 0)
Kripton 显然也支持 static where 条件和许多其他功能(我在 2015 年开始开发它)。
有关 Kripton 持久性库的更多信息:
更新:Room 的最新版本 1.1.1 现在使用 SupportSQLiteQuery 而不是 String。
A query with typed bindings. It is better to use this API instead of rawQuery(String, String[]) because it allows binding type safe parameters.
新答案:
@Dao
interface RawDao {
@RawQuery(observedEntities = User.class)
LiveData<List<User>> getUsers(SupportSQLiteQuery query);
}
用法:
LiveData<List<User>> liveUsers = rawDao.getUsers( new
SimpleSQLiteQuery("SELECT * FROM User ORDER BY name DESC"));
将您的 gradle 更新为 1.1.1(或任何当前版本)
implementation 'android.arch.persistence.room:runtime:1.1.1'
implementation 'android.arch.lifecycle:extensions:1.1.1'
annotationProcessor "android.arch.persistence.room:compiler:1.1.1"