自定义 Android Room Where 条款

时间:2021-07-05 01:55:46

标签: android sqlite android-room

我正在尝试根据 2 个微调字段过滤对象列表。用户可以选择他们想要过滤的字段,而不是所有字段都必须有值(可以留空)。我想写一个查询,而不是在我的 Dao 中编写大量查询。

我的两个字段是颜色和类别。如果选择了特定颜色但未选择类别,则我希望我的查询返回具有该颜色的所有对象,但如果填充了颜色和类别,则我希望我的查询返回这些特定项目,反之亦然。在 SQLite 中,您可以使用它来返回表中所有黑色的对象,而不考虑类别。

Select * from table where colour='black' and category = category

但是当我将变量发送到我的查询时,它会将类别放入引号中,因此房间正在寻找字符串“类别”而不是返回所有类别。 (看起来像这样)

Select * from table where colour='black' and category = 'category'

最终我需要添加更多字段,这就是为什么我不想为每种可能性写出查询。

我考虑过使用 RawQuery,但是我的实现没有奏效。这是我在我的 Dao 中的界面

@interface RawDao
@RawQuery
List<Items> filterdItems(SupportSQLiteQuery query)

在我的课堂上

query = "Select * from table where colour='black' and category = category";
List<items> items = RawDao.filteredItems(query);

但我一直收到错误“无法从静态方法中引用非静态方法...”

有没有办法删除引号,以便在微调器中未选择任何内容时返回所有对象?

3 个答案:

答案 0 :(得分:0)

RawDao 是一个接口,我们不能直接在接口上调用方法,请查看此 link 了解更多信息 How to call an interface method

您需要在RawDao类中创建Database的抽象实例并需要获取Database类的实例

例如:

@Database(entities = {DataClass.class}, version = dbversion in int, exportSchema = false)
public abstract class AppRoomDb extends RoomDatabase {
    private static String TAG = AppRoomDb.class.getSimpleName();
    private static volatile AppRoomDb INSTANCE;
    public abstract RawDao rawDao();

    public static AppRoomDb getInstance(final Context context) {
        if (INSTANCE == null) {
            synchronized (AppRoomDb.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                            AppRoomDb.class, ROOM_DB_NAME)
                            .fallbackToDestructiveMigration()
                            .allowMainThreadQueries()
                            .build();
                }
            }
        }
        return INSTANCE;
    }
}

现在您可以使用以下方法获取 RawDao 接口的方法:

query = "Select * from table where colour='black' and category = category";
List<items> items = AppRoomDb.getInstance(context).rawDao().filteredItems(query);

有关 RoomDb 的更多信息,您可以查看此link

答案 1 :(得分:0)

您正在尝试通过接口名称 filteredItems 访问 RawDao。相反,您应该通过数据库实例调用它。使用数据库实例获取 DAO,然后使用所需的查询调用 filteredItems 方法:

query1 = "Select * from table where colour='black'";
query2 = "Select * from table where category = 'your_category'";
query3 = "Select * from table where colour='black' and category = 'your_category'";
SimpleSQLiteQuery query = new SimpleSQLiteQuery(query1) //Use query1 or query2, query3 
List<items> items = rawDao.filteredItems(query);

答案 2 :(得分:0)

我相信下面的查询会做你想要的(至少在原则上):-

@Query("SELECT * FROM `table` WHERE color = (CASE WHEN length(:color) THEN :color ELSE color END) AND category =  (CASE WHEN length(:category) THEN :category ELSE category END)")
    List<Items> filteredItems(String color, String category);
  • 如果未选择字段,则假定传递空字符串。

以下是一个基于您的代码的工作示例,用于演示上述内容。

它假设颜色和类别是字符串。如果是 id,则 CASE .... WHEN .... THEN .... END 会有所不同,但基本原理是相同的。也就是说,如果提供了合适的值,则使用传递的值,否则使用正在处理的列的值。

  • 如果颜色和类别是 id(长),那么你可以使用
    • @Query("SELECT * FROM table WHERE color = (CASE WHEN :color > 0 THEN :color ELSE color END) AND category = (CASE WHEN :category > 0 THEN :category ELSE category END)") List<Items> filteredItems(String color, String category);

    • 这里假设 id 总是大于 0。

    • 此代码段尚未经过测试/运行,因此可能包含一些错误。

首先是实体表格:-

@Entity
class Table {
    @PrimaryKey
    Long id = null;
    String color = null;
    String category = null;

    public Table(){}
    @Ignore
    public Table(String color, String category) {
        this.color = color;
        this.category = category;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }
}

RawDao 接口:-

@Dao
interface RawDao {

    @Insert
    long insert(Table table);

    @Query("SELECT * FROM `table` WHERE color = (CASE WHEN length(:color) THEN :color ELSE color END) AND category =  (CASE WHEN length(:category) THEN :category ELSE category END)")
    List<Table> filteredItems(String color, String category);
}
  • 为了方便/简洁,请注意使用了列表(基于您查询名为 table 的表,也许它应该是更好的项目)

@Database 类 TheDatabase :-

@Database(entities = {Table.class},version = 1)
abstract class TheDatabase extends RoomDatabase {
    abstract RawDao getDao();

    private static volatile TheDatabase instance = null;

    public static TheDatabase getInstance(Context context) {
        if (instance == null) {
            instance = Room.databaseBuilder(context,TheDatabase.class,"mydb")
                    .allowMainThreadQueries().build();
        }
        return instance;
    }
}

最后一个活动,插入一些行,然后提取数据,使用以下排列将其写入日志:-

  1. 既不是颜色也不是类别(全选)。即传递的空字符串。
  2. 仅传递颜色值
  3. 传递的颜色和类别值
  4. 仅传递了类别值。

:-

public class MainActivity extends AppCompatActivity {

    TheDatabase db;
    RawDao dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        db = TheDatabase.getInstance(this);
        dao = db.getDao();

        dao.insert(new Table("black","cat1"));
        dao.insert(new Table("green","cat1"));
        dao.insert(new Table("black","cat2"));
        dao.insert(new Table("green","cat2"));

        logTableInfo(dao.filteredItems("",""),"RUN1"); /* get everything as no values for either argument */
        logTableInfo(dao.filteredItems("black",""),"RUN2"); /*get color black irrespective of category */
        logTableInfo(dao.filteredItems("black","cat1"),"RUN3"); /* get color black in category cat1 */
        logTableInfo(dao.filteredItems("","cat1"),"RUN4"); /* get all that have cat1 as the category irresepctive of color */
    }

    private void logTableInfo(List<Table> items, String extra) {
        for(Table t: items) {
            Log.d("TABLEINFO" + extra,"Color is " + t.color + " Category is " + t.category + " ID is " + t.id);
        }
    }
}

结果

2021-07-05 21:53:52.616 D/TABLEINFORUN1: Color is black Category is cat1 ID is 1
2021-07-05 21:53:52.617 D/TABLEINFORUN1: Color is green Category is cat1 ID is 2
2021-07-05 21:53:52.617 D/TABLEINFORUN1: Color is black Category is cat2 ID is 3
2021-07-05 21:53:52.617 D/TABLEINFORUN1: Color is green Category is cat2 ID is 4


2021-07-05 21:53:52.619 D/TABLEINFORUN2: Color is black Category is cat1 ID is 1
2021-07-05 21:53:52.619 D/TABLEINFORUN2: Color is black Category is cat2 ID is 3


2021-07-05 21:53:52.619 D/TABLEINFORUN3: Color is black Category is cat1 ID is 1


2021-07-05 21:53:52.620 D/TABLEINFORUN4: Color is black Category is cat1 ID is 1
2021-07-05 21:53:52.620 D/TABLEINFORUN4: Color is green Category is cat1 ID is 2

附加

这是构建一个相对灵活的版本的示例,其中构建了 SQL 并根据注释。

灵活,它不是特定于表/实体,它可以满足任意数量的列/值对(但只有字符串值,BLOB(字节[])必须转换)。使用 ContentValues 可以克服 BLOB 限制)。 然而,与任何@RawQuery 的使用一样,您会失去编译时检查,因此问题将导致运行时错误。

  • 请注意,这并不全面,而是一个可以满足某些情况的示例:-

首先是道:-

@RawQuery
List<Table> filteredItemsAlt(SupportSQLiteQuery query);

然后为了方便起见在表格实体中的一个方法:-

public static SimpleSQLiteQuery buildQuery(String fromClause, String[] whereColumns, String[] whereValues) {

    // Run query that returns nothing if columns and args (values) mismatch
    SimpleSQLiteQuery rv = new SimpleSQLiteQuery(fromClause + " WHERE 1 = 2", null);
    if (whereColumns.length != whereValues.length) return rv;
    // OK to go so prepare build variables
    ArrayList<String> bindArgs = new ArrayList<>();
    StringBuilder whereclause = new StringBuilder();
    
    // For each column and therefore arg/value
    for(int i=0; i < whereColumns.length; i++) {
        if (whereclause.length() > 1) whereclause.append(" AND "); // if where clause is not empty then add AND
        whereclause.append(whereColumns[i]).append(" = "); // column name = part
        // if value/arg is null or string is empty then affectively ignore (could alternatively ignore the AND and column = column)
        if (whereValues[i] == null || whereValues[i].length() < 1) whereclause.append(whereColumns[i]);
        // otherwise prepare to bind the value i.e ? in the SQL and value stored for bind
        else {
            whereclause.append(" ? ");
            bindArgs.add(whereValues[i]);
        }
    }
    Log.d("WHERE_CLAUSE","WHERE clause is " + whereclause.toString());
    // check to se if there is a where clause, if so build the full SQL
    if (whereclause.length() > 0 ) {
        rv = new SimpleSQLiteQuery(fromClause + " WHERE " + whereclause.toString(), bindArgs.toArray());
    } else {
        // otherwise build sql without WHERE clause
        rv = new SimpleSQLiteQuery(fromClause);
    }
    return rv;
}
  • fromClause 是包含 fromClause 的 SELECT SQL
  • whereColumns 是要比较的列的列表
  • whereValues 是值列表(空或空字符串以获取列的所有行)

在活动中(复制第一个结果),您可以:-

    logTableInfo(dao.filteredItemsAlt(Table.buildQuery(
            "SELECT * FROM `table`",
            new String[]{"color","category"},
            new String[]{null,null}
    )),"ARUN1");
    logTableInfo(dao.filteredItemsAlt(Table.buildQuery(
            "SELECT * FROM `table`",
            new String[]{"color","category"},
            new String[]{"black",null}
    )),"ARUN2");
    logTableInfo(dao.filteredItemsAlt(Table.buildQuery(
            "SELECT * FROM `table`",
            new String[]{"color","category"},
            new String[]{"black","cat1"}
    )),"ARUN3");
    logTableInfo(dao.filteredItemsAlt(Table.buildQuery(
            "SELECT * FROM `table`",
            new String[]{"color","category"},
            new String[]{null,"cat1"}
    )),"ARUN4");

结果:-

2021-07-06 17:07:14.840 D/WHERE_CLAUSE: WHERE clause is color = color AND category = category
2021-07-06 17:07:14.841 D/TABLEINFOARUN1: Color is black Category is cat1 ID is 1
2021-07-06 17:07:14.841 D/TABLEINFOARUN1: Color is green Category is cat1 ID is 2
2021-07-06 17:07:14.841 D/TABLEINFOARUN1: Color is black Category is cat2 ID is 3
2021-07-06 17:07:14.841 D/TABLEINFOARUN1: Color is green Category is cat2 ID is 4
2021-07-06 17:07:14.841 D/WHERE_CLAUSE: WHERE clause is color =  ?  AND category = category
2021-07-06 17:07:14.843 D/TABLEINFOARUN2: Color is black Category is cat1 ID is 1
2021-07-06 17:07:14.843 D/TABLEINFOARUN2: Color is black Category is cat2 ID is 3
2021-07-06 17:07:14.843 D/WHERE_CLAUSE: WHERE clause is color =  ?  AND category =  ? 
2021-07-06 17:07:14.846 D/TABLEINFOARUN3: Color is black Category is cat1 ID is 1
2021-07-06 17:07:14.847 D/WHERE_CLAUSE: WHERE clause is color = color AND category =  ? 
2021-07-06 17:07:14.849 D/TABLEINFOARUN4: Color is black Category is cat1 ID is 1
2021-07-06 17:07:14.849 D/TABLEINFOARUN4: Color is green Category is cat1 ID is 2
  • 请注意,上述内容是相对仓促地组合在一起的,因此可能可以进行一些调整,因此更多的是一个原则性示例。 例如如果你想订购怎么办? (修辞)
相关问题