5

我想在运行时生成的 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 实现并查看了它正在运行的语句。这确认了生成的查询信息,并且查询正在正确传递。我认为这是防止 SQL 注入的问题(也就是 SQLITE 问题,而不是 Room 问题) 在此处输入图像描述

4

2 回答 2

15

更新:Room 的最新版本 1.1.1 现在使用 SupportSQLiteQuery 而不是 String。

带有类型绑定的查询。最好使用此 API 而不是 rawQuery(String, String[]),因为它允许绑定类型安全参数。

新答案:

@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"
于 2018-03-17T02:19:33.147 回答
0

问题是您想传递 SQL 语句的一部分,但 Room 将其视为查询参数。

如果您愿意,可以尝试使用 Kripton Persistence Library,这是一个开源库(由我编写 :)),它极大地简化了 SQLite 针对 Android 平台的管理代码并支持此类情况。

Kripton 也适用于 DAO 模式,因此概念非常相似。只是写一个适合您需求的示例:

给定一个模型类:

@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 显然也支持静态条件和许多其他功能(我在 2015 年开始开发它)。

有关 Kripton 持久性库的更多信息:

于 2017-09-08T01:17:12.957 回答