我正在尝试根据 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);
但我一直收到错误“无法从静态方法中引用非静态方法...”
有没有办法删除引号,以便在微调器中未选择任何内容时返回所有对象?
答案 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
会有所不同,但基本原理是相同的。也就是说,如果提供了合适的值,则使用传递的值,否则使用正在处理的列的值。
@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);
}
@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;
}
}
最后一个活动,插入一些行,然后提取数据,使用以下排列将其写入日志:-
:-
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 SQLwhereColumns
是要比较的列的列表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