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

时间:2017-05-31 14:27:31

标签: 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);

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


更复杂的用例

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

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

10 个答案:

答案 0 :(得分:15)

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

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

答案 1 :(得分:11)

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

官方文档 - &gt; 如果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);

并在您不想应用过滤器时传递否定。

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

这是我的工作。

更新[2018年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>

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

答案 2 :(得分:6)

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

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

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

以下是您可以使用它的方法:

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

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

重要提示:这可在会议室1.1.0-alpha3

中找到

答案 3 :(得分:6)

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


步骤1:制作DAO方法

.sort()注释而不是普通的@RawQuery标记DAO方法。

@RawQuery


第2步:构造查询

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

在此示例中,我将变量@Dao interface BooksDao{ @RawQuery List<Book> getBooks(SupportSQLiteQuery query); } 用于查询字符串,将queryString用于绑定参数。

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

args


第3步:执行查询

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




注释

  • 像普通的SimpleSQLiteQuery query = new SimpleSQLiteQuery(queryString, args.toArray()); List<Book> result = booksDao.getBooks(query); 一样,Query支持返回具有嵌入字段的原始光标,实体,POJO和POJO
  • RawQuery支持关系

答案 4 :(得分:4)

使用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个且只有1个参数类型为String   或SupportSQLiteQuery

答案 5 :(得分:1)

使其更简单。我将向您展示使用两个变量的where子句的示例。这样做:

  @Query("SELECT * FROM Student WHERE stdName1= :myname AND stdId1=:myid")
List<Student> fetchAllData(String myname,int myid);

stdName1和stdId1是列名

答案 6 :(得分:0)

  @Query("select * from task where state = :states and sentdate between :fromdate and :todate")
  List<Task> getFilterAll(String states, String fromdate, String todate);

在这里我们需要使用列名状态。每当需要实现自定义查询时,只需通过活动中的参数传递值即可,否则碎片会进入我们将在查询内部应用的接口。就像上面代码(:fromdate:todate)中的示例一样

冒号是必须的。在查询中将使用哪个参数,我们将在以:符号开头之前提到。

答案 7 :(得分:0)

对于 Kotlin-Room-ViewModel

@Query("SELECT * FROM schedule_info_table where schedule_month = :monthValue ORDER BY schedule_date_time ASC")
fun getThisMonthSchedules(monthValue: Int): Flow<List<SchedulesInformation>>

答案 8 :(得分:-1)

@Anderson K&amp; @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类。

答案 9 :(得分:-2)

根据 documentation

不推荐使用原始查询