如何在运行时动态查询会议室数据库?

And*_*n K 26 android android-room

问题

是否有可能在运行时构造一个查询?


用例

@Query("SELECT * FROM playlist " +
        "WHERE playlist_title LIKE '% :playlistTitle %' " +
        "GROUP BY playlist_title " +
        "ORDER BY playlist_title " +
        "LIMIT :limit")
 List<IPlaylist> searchPlaylists(String playlistTitle, int limit);
Run Code Online (Sandbox Code Playgroud)

limit部分是可选的.也就是说,它应该能够在有或没有限制的情况下执行相同的查询.


一个更复杂的用例

在前一种情况下,可以使用和不使用限制部分进行两个静态查询,并且每次都可以使用适当的一个.但有时我们可能不得不处理更复杂的情况,例如构建过滤器.

在这种情况下,与前面的示例不同,将有多个可选部分.对于书籍表,我们可能需要根据书籍所属的类别,作者姓名,价格范围,出版日期等进行过滤.使用这些部分的所有组合进行静态查询几乎是不可能的.

小智 18

根据我的经验(简称)使用不可能的房间,而不是因为房间限制,而是由@CommonsWare隐含评论,SQLite的限制.您需要两个查询,因此DAO中有两个方法.

我会有类似的东西:

@Query("SELECT * FROM playlist " +
    "WHERE playlist_title LIKE '% :playlistTitle %' " +
    "GROUP BY playlist_title " +
    "ORDER BY playlist_title " +
    "LIMIT :limit")
List<IPlaylist> searchPlaylists(String playlistTitle, int limit);

@Query("SELECT * FROM playlist " +
    "WHERE playlist_title LIKE '% :playlistTitle %' " +
    "GROUP BY playlist_title " +
    "ORDER BY playlist_title ")
List<IPlaylist> searchPlaylists(String playlistTitle);
Run Code Online (Sandbox Code Playgroud)

然后在其他地方你做旁路:

if (limit.isPresent()) {
   return playlistDao.searchPlaylists(title, limit.get());
} else {
   return playlistDao.searchPlaylists(title);
}
Run Code Online (Sandbox Code Playgroud)

这是我现在能想到的最佳选择.

  • 您好,在我的情况下它不起作用。特别是这一行“WHERE playlist_title LIKE '% :playlistTitle %'” (2认同)
  • 当我使用此方法时,“playlistTitle”未使用错误会发生 (2认同)
  • 这是一个很好的答案。但自从 Room 引入 [`@RawQuery`](/sf/answers/3633785991/) 注释以来,它已经过时了。 (2认同)
  • 您需要将房间查询字符串与 || 连接起来 所以这里变成: LIKE '%' || :播放列表标题 || '%' 。还可以用 || 连接所有内容 (2认同)

Moi*_*han 15

我没有写多个查询,而是将负值传递给limit子句.因为如果查询中有变化,我必须更新两个查询,这更容易出错.

官方文档 - > 如果LIMIT表达式求值为负值,则返回的行数没有上限.你可以在这里找到它https://sqlite.org/lang_select.html并阅读限制条款部分.

所以我会做这样的事,

@Query("SELECT * FROM playlist " +
    "WHERE playlist_title LIKE '% :playlistTitle %' " +
    "GROUP BY playlist_title " +
    "ORDER BY playlist_title " +
    "LIMIT :limit")
List<IPlaylist> searchPlaylists(String playlistTitle, int limit);
Run Code Online (Sandbox Code Playgroud)

并且当您不想应用过滤器时传递否定.

return playlistDao.searchPlaylists(title, limit.isPresent() ? limit.get() : -1)
Run Code Online (Sandbox Code Playgroud)

它在我的情况下工作.

更新[201年12月21日]

如果您使用kotlin使用默认值.

@JvmOverloads
@Query("SELECT * FROM playlist " +
        "WHERE playlist_title LIKE '% :playlistTitle %' " +
        "GROUP BY playlist_title " +
        "ORDER BY playlist_title " +
        "LIMIT :limit")
fun searchPlaylists(playlistTitle: String, limit: Int = -1): List<IPlaylist>
Run Code Online (Sandbox Code Playgroud)

@JvmOverloads使其与Java兼容.它为Java生成两个单独的方法.


Ber*_*yle 12

Room支持@RawQuery注释以在运行时构造查询。


步骤1:制作DAO方法

@RawQuery注解而不是normal 标记DAO方法@Query

@Dao
interface BooksDao{
    @RawQuery
    List<Book> getBooks(SupportSQLiteQuery query);
}
Run Code Online (Sandbox Code Playgroud)


步骤2:构建查询

Room使用准备好的语句进行安全性和编译时间验证。因此,在构造查询时,我们需要分别存储查询字符串和绑定参数。

在此示例中,我将变量queryString用于查询字符串和args绑定参数。

(请注意,我使用文本编辑器编写代码。因此,可能会出现拼写错误或简单的语法错误。如果发现任何问题,请在评论中告知我或编辑帖子。)

// Query string
String queryString = new String();

// List of bind parameters
List<Object> args = new ArrayList();

boolean containsCondition = false;

// Beginning of query string
queryString += "SELECT * FROM BOOKS";

// Optional parts are added to query string and to args upon here

if(!authorName.isEmpty()){
    queryString += " WHERE";
    queryString += " author_name LIKE ?%";
    args.add(authorName);
    containsCondition = true;
}

if(fromDate!=null){

    if (containsCondition) {
        queryString += " AND";
    } else {
        queryString += " WHERE";
        containsCondition = true;
    }

    queryString += " publication_date AFTER ?";
    args.add(fromDate.getTime());
}

if(toDate!=null){

    if (containsCondition) {
        queryString += " AND";
    } else {
        queryString += " WHERE";
        containsCondition = true;
    }

    queryString += " publication_date BEFORE ?";
    args.add(toDate.getTime());
}

// End of query string
queryString += ";";
Run Code Online (Sandbox Code Playgroud)


步骤3:执行查询

SimpleSQLiteQuery query = new SimpleSQLiteQuery(queryString, args.toArray());
List<Book> result = booksDao.getBooks(query);
Run Code Online (Sandbox Code Playgroud)




笔记

  • 与正常情况一样QueryRawQuery支持返回带有嵌入式字段的原始光标,实体,POJO和POJO
  • RawQuery 支持关系

  • 这应该是公认的答案,因为它解决了原始问题。 (3认同)
  • @RawQuery 是否存在 SQL 注入攻击的风险,因此存在安全风险? (2认同)
  • 不。它不是纯文本查询,因为名称让我们想到。它在内部使用绑定变量。[SimpleSQLiteQuery](https://developer.android.com/reference/android/arch/persistence/db/SimpleSQLiteQuery),更准确地说。 (2认同)
  • 我想推荐一些使这项工作变得更容易的课程。我期待您的反馈。[UpdateRawQueryBuilder](https://bitbucket.org/tim4dev/workspace/snippets/4nb4eg) [SimpleQueryBuilder](https://bitbucket.org/tim4dev/workspace/snippets/zndzeb) (2认同)

Mla*_*jac 7

在Room中没有类似可选参数的东西,但是有一个@RawQuery注释,您可以在其中将查询作为String传递,以便您可以在运行时中构建SQL查询.我认为这对你有用.

以下是官方文档中的示例:

@Dao
 interface RawDao {
     @RawQuery
     User getUser(String query);
 }
Run Code Online (Sandbox Code Playgroud)

以下是如何使用它:

User user = rawDao.getUser("SELECT * FROM User WHERE id = 3 LIMIT 1");
Run Code Online (Sandbox Code Playgroud)

重要说明: RawQuery方法必须返回非void类型

重要提示:这可在1.1.0-alpha3室中找到


liv*_*ove 7

使用 SupportSQLiteQuery。

https://developer.android.com/reference/android/arch/persistence/db/SupportSQLiteQuery

最新版本 1.1.1 现在使用 SupportSQLiteQuery。

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

@Dao
     interface RawDao {
         @RawQuery(observedEntities = User.class)
         LiveData<List<User>> getUsers(SupportSQLiteQuery query);
     }
Run Code Online (Sandbox Code Playgroud)

用法:

     LiveData<List<User>> liveUsers = rawDao.getUsers( new 
SimpleSQLiteQuery("SELECT * FROM User ORDER BY name DESC"));
Run Code Online (Sandbox Code Playgroud)

将您的 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"
Run Code Online (Sandbox Code Playgroud)

注意:如果您升级到 1.1.1,并且使用 String 而不是 SupportSQLiteQuery,

你会得到错误:

RawQuery 不再允许传递字符串。请使用 android.arch.persistence.db.SupportSQLiteQuery。

使用上面的 SupportSQLiteQuery 可以解决这个问题。

注意:确保传入 SupportSQLiteQuery 查询参数,否则会出现此错误:

RawQuery 方法应该有 1 个且只有 1 个类型为 String 或 SupportSQLiteQuery 的参数