Android会议室:订单不工作

时间:2017-05-29 11:01:14

标签: android android-room android-architecture-components

我正在使用新的Android ORM Room。 我遇到了以下问题,使用带有参数的ORDER BY的查询无效。

如果我想使用从ORDER BY的参数填充的字段,它不起作用。它只是没有任何排序。

@Query("SELECT * FROM User ORDER BY :orderBY ASC")
List<User> sortedFind(String orderBY);

但是,当我直接在查询中放置ORDER BY列来对结果进行排序时,它会按预期工作。

@Query("SELECT * FROM User ORDER BY name ASC")
List<User> sortedFind();

它是Android Room上的错误,还是我做错了什么?

4 个答案:

答案 0 :(得分:7)

发生了什么

您可以作为参数传递给@Dao方法的唯一值是值,而不是查询字符串。这个(我相信)的原因是为了防止SQL注入问题。

为何会出现这种情况

例如,查询SELECT * emails WHERE uid = ?然后将值设置为"1 OR WHERE isAdmin = true"。这将允许人们在您的数据库上运行他们自己的定制查询并执行他们想要的操作。

我的解决方案

我也遇到了这个问题。这是我solution的链接。

我的解决方案有2个部分。首先根据输入生成查询字符串和值数组的DynamicQueryservice,然后运行原始查询并返回Cursor。第二,Cursor2POJO映射器,所以我不必为类反复写出游标映射,也不会引入潜在的维护问题。我只是在我的类中添加注释(与房间列名称匹配),lib处理其余的。

为了您的利益,我已将我的Cursor映射器分离为自己的library,随意使用它(如果自述文件不清楚,或者在评论中有错误,我就这样做了) 。

P.S。我的库不能使用Room @ColumnInfo来获取列名,因为注释当前设置为RetentionPolicy.CLASS,因此无法通过反射访问。 (已添加到Google问题跟踪器https://issuetracker.google.com/issues/63720940

答案 1 :(得分:1)

您应使用@RawQuery批注和SupportSQLiteQuery类进行运行时查询

在道:

 @RawQuery
 List<Objects> runtimeQuery(SupportSQLiteQuery sortQuery);

要获取数据:

String query ="SELECT * FROM User ORDER BY " + targetField + " ASC";
List<Objects> users = appDatabase.daoUser().runtimeQuery(new SimpleSQLiteQuery(query));

答案 2 :(得分: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> sortedFind(@BindSqlDynamicOrderBy String orderBy);
}

和数据源定义:

@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();
    dao.sortedFind("name asc");
    return true;
  }
});

在logcat中执行上面的代码时,您将看到生成的日志:

database OPEN READ_AND_WRITE_OPENED (connections: 1)
SELECT id, name, username, email, address, phone, website, company FROM user ORDER BY name asc
Rows found: 0
database CLOSED (READ_AND_WRITE_OPENED) (connections: 0)

Kripton显然也支持静态秩序以及许多其他功能(我在2015年开始开发它)。

有关Kripton Persistence Library的更多信息:

答案 3 :(得分:0)

您只能参考任何列的名称按升序排列数据。 以编程方式,您不能将任何值传递给Dao方法