【问题标题】:Room database RawQuery() is not work on "IN" and "NOT IN" clause房间数据库 RawQuery() 不适用于“IN”和“NOT IN”子句
【发布时间】:2021-11-17 10:53:33
【问题描述】:

我有一个像 UserTable 这样的表。

@Entity
public class UserTable{
  @PrimaryKey(autoGenerate = true)
    private int userId;
    private String userName;
    private String userEmailId;

  // Below code is getter and setter of this class.
}

@Dao
public interface UserDao {
    @Query("SELECT * FROM userTable")
    public List<UserTable> loadAllUsers();

    @Insert
    public long insertUserTable(UserTable userTable);

    @Insert
    public long[] insertUserTables(UserTable... userTables);

    @Update
    public int updateUserTable(UserTable userTable);

    @Delete
    public int deleteUserTable(UserTable userTable);

    @RawQuery
    public abstract List<UserTable> loadAllUserListByGivenIds
            (SupportSQLiteQuery query);

    public default List<UserTable> loadAllUserListByIds(long[] userIds) {
        List<UserTable> list;
        ArrayList<Object> argsList = new ArrayList<>();
        String selectQuery = "SELECT  * FROM UserTable WHERE userId IN (?);";
        argsList.add(userIds);
        
        SimpleSQLiteQuery simpleSQLiteQuery = new SimpleSQLiteQuery(selectQuery, argsList.toArray());
        list = loadAllUserListByGivenIds(simpleSQLiteQuery);
        return list;
    }
}

// 现在在我的 MainActivity.class 文件中,我使用了以下代码:

 List<UserTable> userList= databaseClient
                .getAppDatabase()
                .userDao()
                .loadAllUserListByIds(new long[]{1L,2L});

我的查询在普通数据库中运行,但是当我传递用户 ID 数组时,在 dao 类的 @RawQuery() 方法中,在 where 条件“WHERE userId IN (?) ”。

如何,我将在房间数据库的@RawQuery() 中使用“IN”子句。

【问题讨论】:

    标签: java android database sqlite android-room


    【解决方案1】:

    @Query 使用起来要容易得多,它很简单:-

    @Query("SELECT * FROM UserTable WHERE userId IN (:idList)")
    public List<UserTable> getWhatever(long[] idList);
    

    然后你会使用getWhatever(new long[]{1L,2L})

    如果你需要@rawQuery,尽管你可以这样做(为方便起见,使用以前的答案代码):-

    private List<TableXEntity> loadAllUserListByIds(int order,long[] idList) {
        StringBuilder idListAsCSV = new StringBuilder(); //<<<<<<<<<<
        boolean afterFirst = false; //<<<<<<<<<<
        //<<<<<<<<<< all of the loop to create the CSV
        for (Long l: idList) {
            if (afterFirst) {
                idListAsCSV.append(",");
            }
            afterFirst = true;
            idListAsCSV.append(String.valueOf(l));
        }
        StringBuilder sb = new StringBuilder("SELECT * FROM ").append(DBHelper.TableX.NAME);
        sb.append(" WHERE " + DBHelper.TableX.COLUMN_ID + " IN(").append(idListAsCSV).append(") "); //<<<<<<<<<<
        switch (order) {
            case DBHelper.TableX.FIRSTNAME_DESCENDING:
                sb.append(DBHelper.TableX.ORDER_BY_FIRSTNAME_DESC);
                break;
            case DBHelper.TableX.FIRSTNAME_ASCENDING:
                sb.append(DBHelper.TableX.ORDER_BY_FIRSTNAME_ASC);
                break;
            case DBHelper.TableX.LASTNAME_DESCENDING:
                sb.append(DBHelper.TableX.ORDER_BY_LASTNAME_DESC);
                break;
            case DBHelper.TableX.LASTNAME_ASCENDING:
                sb.append(DBHelper.TableX.ORDER_BY_LASTNAME_ASC);
                break;
            default:
                break;
        }
        sb.append(";");
        return roomDao.rawq(new SimpleSQLiteQuery(sb.toString(),null));
    }
    

    即提供一个 CSV (虽然我隐约记得能够传递一个数组)


    要使用绑定参数(作为绑定参数的推荐方法可以防止 SQL 注入),那么您需要一个 ?对于每个值和相应的对象数组。

    因此,对于 3 个 id,您需要 IN(?,?,?) 和 Object[] 中的实际值、绑定参数。以下是执行此操作的示例,注意它显示了构建 Object[](绑定参数/值)的 2 种方法:-

    private List<TableXEntity> loadByidList(long[] idlist) {
        List<Object> bindargs = new ArrayList<>(); // way 1
        Object[] args4Bind = new Object[idlist.length]; // way 2
        StringBuilder placeholders = new StringBuilder(); // for the ? placeholders
        /* Build the sql before the place holders */
        StringBuilder sql = new StringBuilder("SELECT * FROM ")
                .append(DBHelper.TableX.NAME)
                .append(" WHERE ")
                .append(DBHelper.TableX.COLUMN_ID)
                .append(" IN (");
        boolean afterfirst = false;
        int i = 0; /* using for each so have index counter (as opposed to for(int i=0 ....) */
        for (long l: idlist) {
            bindargs.add(l); // for way 1
            args4Bind[i++] = String.valueOf(l); // for way 2
            if (afterfirst) {
                placeholders.append(",");
            }
            afterfirst = true;
            placeholders.append("?");
        }
        /* finalise the SQL */
        sql.append(placeholders.toString())
                .append(");");
        //return roomDao.rawq(new SimpleSQLiteQuery(sql.toString(),bindargs.toArray())); // way 1
        return roomDao.rawq(new SimpleSQLiteQuery(sql.toString(),args4Bind)); // way 2
    }
    

    【讨论】:

    • @MayurMisal 正在为内部@RawQuery 编写和测试(才意识到你之前的问题是@RawQuery
    【解决方案2】:

    请试试这个,它已经工作了!

    试试这个简单的技巧来传递 IN 运算符的参数-

    List<Object> argList = new ArrayList<>();
     argList.add("3");
     argList.add("6");
    
        
    

    然后准备你的原始查询字符串:

    注意 - 将您的参数列表大小与“?”匹配尺寸

       String selectQuery = "SELECT * FROM task WHERE id IN (?,?)";
    

    之后将原始查询字符串传递给 SimpleSQLiteQuery-

       SimpleSQLiteQuery rawQuery = new SimpleSQLiteQuery(selectQuery, args.toArray());
    

    然后使用 DAO 获取列表:

    List<UserTable> taskList1=DatabaseClient
                            .getInstance(getApplicationContext())
                            .getAppDatabase()
                            .userTableDAO()
                            .getAllList(query);
    

    【讨论】:

    • 谢谢萨钦·德什潘德!!!我已经尝试过了,但有时它可以工作,有时不能。所以我使用了 MikeT 答案,将字符串连接起来,然后在 @RawQuery() 中触发它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-12
    • 1970-01-01
    • 1970-01-01
    • 2015-09-28
    • 2021-08-20
    • 2017-01-30
    相关资源
    最近更新 更多