首页 文章

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

提问于
浏览
18

问题

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

用例

@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);

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

更复杂的用例

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

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

7 回答

  • 5

    @Anderson K&@Juanky Soriano,我同意@CommonsWare,

    房间库中有一些限制,那么我们也可以使用支持SQLite数据库的@query()在房间数据库上编写完全动态的查询

    String mQuery = "SELECT * FROM foobar WHERE columnName1 IN ('value_1','value_2') and columnName2 In('value_3','value_4')";
    
    AppDatabase appDatabase = Room.databaseBuilder(getApplicationContext(),
            AppDatabase.class, "database-name").build();
    
    Cursor mCursor = AppDatabase.getAppDatabase(context).getOpenHelper().getReadableDatabase().query(myQuery);
    

    现在,您可以将游标行方式数据转换为POJO类 .

  • -1

    根据我的经验(简称)使用不可能的房间,而不是因为房间限制,而是由@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);
    

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

    if (limit.isPresent()) {
       return playlistDao.searchPlaylists(title, limit.get());
    } else {
       return playlistDao.searchPlaylists(title);
    }
    

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

  • 6

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

    官方文档 - > If the LIMIT expression evaluates to a negative value, then there is no upper bound on the number of rows returned. 你可以在这里找到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);
    

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

    return playlistDao.searchPlaylists(title, limit.isPresent() ? limit.get() : -1)
    

    它在我的情况下工作 .

    Updated [21 Dec 2018]

    如果您使用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>
    

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

  • 10

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

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

    @Dao
     interface RawDao {
         @RawQuery
         User getUser(String query);
     }
    

    以下是如何使用它:

    User user = rawDao.getUser("SELECT * FROM User WHERE id = 3 LIMIT 1");
    

    Important: RawQuery方法必须返回非void类型

    Important: 这可以在房间1.1.0-alpha3中找到

  • 4

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

    步骤1:制作DAO方法

    使用 @RawQuery 注释而不是正常 @RawQuery 标记DAO方法 .

    @Dao
    interface BooksDao{
        @RawQuery
        List<Book> getBooks(SupportSQLiteQuery query);
    }
    

    步骤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 += ";";
    

    步骤3:执行查询

    SimpleSQLiteQuery query = new SimpleSQLiteQuery(queryString, args.toArray());
    List<Book> result = booksDao.getBooks(query);
    

    注意事项

    • 与普通 Query 一样, RawQuery 支持使用嵌入字段返回原始游标,实体,POJO和POJO

    • RawQuery 支持关系

  • 15

    使用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);
         }
    

    用法:

    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"
    

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

    你会得到错误:

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

    如上所述使用SupportSQLiteQuery将解决问题 .

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

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

  • 1
    make it more simple.i will show you example using where clause using two variable.Do 
    like this
    
      @Query("SELECT * FROM Student WHERE stdName1= :myname AND stdId1=:myid")
    List<Student> fetchAllData(String myname,int myid);
    

    stdName1和stdId1是列名

相关问题