如何在 android 房间加入查询中的内部 table 中制作过滤器
How to make filter in inner table in android room join query
我有两个 tables table A 和 table B,我正在 android 房间进行内部连接查询(A 内部连接 B),但是我必须从 table B 过滤数据,在 android 房间可以吗?
是的,但您必须了解 Room 的工作原理以及 JOIN 的工作原理(即笛卡尔积,每个与过滤器匹配的组合都会有一行)
通常你会使用 POJO 和 TableA Embedded
(@Embedded
) 和 TableB 作为一个 @Relation
进行组合。例如:-
class TableAWithTableB {
@Embedded
TableA tableA;
@Relation(entity = TableB.class,parentColumn = "tableAId", entityColumn = "tableAMapId")
List<TableB> tableBList;
}
然而,Room 处理 @Relation
的方式是它只从结果中检索 parent,然后继续获取 parent 的所有 children .也就是说,如果过滤器在 child.
上,它会构建一个完整的 object 忽略过滤器
如果你想在 children 上应用过滤器,那么你将不会使用 @Relation
但可以 @Embedded
同时使用 parent 和 child 但是然后你得到每个 child 的 parent,所以可以有多个相同的 parent。例如
class TableAJoinedWithTableB {
@Embedded
TableA tableA;
@Embedded
TableB tableB;
}
例子
考虑到这两个实体是:-
@Entity
class TableA {
@PrimaryKey
Long tableAId;
String nameA;
public TableA(){}
@Ignore
public TableA(String name){
this.nameA = name;
}
public Long getTableAId() {
return tableAId;
}
public void setTableAId(Long tableAId) {
this.tableAId = tableAId;
}
public String getName() {
return nameA;
}
public void setName(String name) {
this.nameA = name;
}
}
和:-
@Entity(
foreignKeys = {
@ForeignKey(
entity = TableA.class,
parentColumns = "tableAId",
childColumns = "tableAMapId"
)
}
)
class TableB {
@PrimaryKey
Long tableBId;
@ColumnInfo(index = true)
Long tableAMapId;
String nameB;
public TableB(){}
@Ignore
public TableB(long tableAMapId,String name) {
this.tableAMapId = tableAMapId;
this.nameB = name;
}
public Long getTableBId() {
return tableBId;
}
public void setTableBId(Long tableBId) {
this.tableBId = tableBId;
}
public Long getTableAMapId() {
return tableAMapId;
}
public void setTableAMapId(Long tableAMapId) {
this.tableAMapId = tableAMapId;
}
public String getName() {
return nameB;
}
public void setName(String name) {
this.nameB = name;
}
}
和@Dao,AllDao,是:-
@Dao
interface AllDao {
@Insert long insert(TableA tableA);
@Insert long[] insert(TableA...one_or_more_tableAs);
@Insert long insert(TableB tableB);
@Insert long[] insert(TableB...one_or_moretableBs);
@Query("DELETE FROM tableA") int deleteAllFROMTableA();
@Query("DELETE FROM tableB") int deleteAllFromTableB();
@Query("SELECT * FROM tablea") List<TableA> getALlFromTableA();
@Query("SELECT * FROM tableb") List<TableB> getAllFromTableB();
@Transaction @Query("SELECT tableA.* FROM tablea JOIN tableb ON tableAId = tableAMapId WHERE tableb.nameB >:arg")
List<TableAWithTableB> getSelectedViaRelation(String arg);
@Query("SELECT * FROM tablea JOIN tableb ON tableAId = tableAMapId WHERE tableb.nameB >:arg")
List<TableAJoinedWithTableB> getSelectedViaEmbedded(String arg);
}
@Database class 是 TheDatabase(一个非常标准的)然后使用 :-
public class MainActivity extends AppCompatActivity {
TheDatabase db;
AllDao dao;
private static final String TAG = "TABLEINFO";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = TheDatabase.getInstance(this);
dao = db.getDao();
dao.deleteAllFromTableB();
dao.deleteAllFROMTableA();
long row1Id = dao.insert(new TableA("ROW1"));
long row2Id = dao.insert(new TableA("ROW2"));
long row3Id = dao.insert(new TableA("ROW3"));
long row4Id = dao.insert(new TableA("ROW4"));
dao.insert(new TableB(row1Id,"A"));
dao.insert(new TableB(row1Id,"Z"));
dao.insert(new TableB(row1Id,"P"));
dao.insert(new TableB(row2Id,"B"));
dao.insert(new TableB(row2Id,"Y"));
dao.insert(new TableB(row2Id,"O"));
dao.insert(new TableB(row3Id,"C"));
dao.insert(new TableB(row3Id,"X"));
dao.insert(new TableB(row3Id,"N"));
dao.insert(new TableB(row4Id,"AA"));
dao.insert(new TableB(row4Id,"BB"));
for(TableAWithTableB t: dao.getSelectedViaRelation("M")) {
logTableA(t.tableA);
for(TableB tb: t.tableBList) {
logTableB(tb);
}
}
for (TableAJoinedWithTableB t: dao.getSelectedViaEmbedded("M")) {
Log.d(TAG,"TableA is " + t.tableA.getName() + " TableB is " + t.tableB.getName() + " Parent(TableA) ID is " + t.tableB.getTableAMapId());
}
}
private void logTableA(TableA tableA) {
Log.d(TAG,"TableA Name = " + tableA.getName());
}
private void logTableB(TableB tableB) {
Log.d(TAG,"\tTableB = " + tableB.getName() + " Parent TableA is " + tableB.getTableAMapId());
}
}
结果:-
2021-06-29 07:43:49.134 D/TABLEINFO: TableA Name = ROW1
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = A Parent TableA is 1
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = Z Parent TableA is 1
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = P Parent TableA is 1
2021-06-29 07:43:49.134 D/TABLEINFO: TableA Name = ROW1
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = A Parent TableA is 1
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = Z Parent TableA is 1
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = P Parent TableA is 1
2021-06-29 07:43:49.134 D/TABLEINFO: TableA Name = ROW2
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = B Parent TableA is 2
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = Y Parent TableA is 2
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = O Parent TableA is 2
2021-06-29 07:43:49.135 D/TABLEINFO: TableA Name = ROW2
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = B Parent TableA is 2
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = Y Parent TableA is 2
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = O Parent TableA is 2
2021-06-29 07:43:49.135 D/TABLEINFO: TableA Name = ROW3
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = C Parent TableA is 3
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = X Parent TableA is 3
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = N Parent TableA is 3
2021-06-29 07:43:49.135 D/TABLEINFO: TableA Name = ROW3
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = C Parent TableA is 3
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = X Parent TableA is 3
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = N Parent TableA is 3
2021-06-29 07:43:49.140 D/TABLEINFO: TableA is ROW1 TableB is Z Parent(TableA) ID is 1
2021-06-29 07:43:49.140 D/TABLEINFO: TableA is ROW1 TableB is P Parent(TableA) ID is 1
2021-06-29 07:43:49.140 D/TABLEINFO: TableA is ROW2 TableB is Y Parent(TableA) ID is 2
2021-06-29 07:43:49.140 D/TABLEINFO: TableA is ROW2 TableB is O Parent(TableA) ID is 2
2021-06-29 07:43:49.140 D/TABLEINFO: TableA is ROW3 TableB is X Parent(TableA) ID is 3
2021-06-29 07:43:49.140 D/TABLEINFO: TableA is ROW3 TableB is N Parent(TableA) ID is 3
因此 ROW4 不存在,由于过滤,在任何一种方法中 BUT:-
with @Relation
for TableB,结果是完整的Table A objects忽略了关于children的WHERE子句。
当对 TableB 使用 @Embedded
时,将应用过滤器,但是 parent 会得到多行(就像没有空间一样)。
额外
如果您想部分构建 TableA objects,即使用选择性 children,那么您必须完成基础工作(就像您必须使用原生 SQLite)。您可以根据 getSelectedViaEmbedded 的结果构建它们,方法是将相同的 TableA 合并到任一 POJO classes 中(如果不是,注释将被忽略按房间建造)。例如考虑:-
class TableAsWithSelectiveTableB {
private ArrayList<TableAWithTableB> tableAWithTableBList = new ArrayList<>();
private TableAsWithSelectiveTableB(List<TableAJoinedWithTableB> baselist) {
String previousTableAName = "";
TableA currentTableA = null;
ArrayList<TableB> currentTableBList = new ArrayList<>();
boolean toBeApplied = false;
for (TableAJoinedWithTableB tabj: baselist) {
if (!tabj.tableA.nameA.equals(previousTableAName)) {
if (toBeApplied) {
TableAWithTableB apply = new TableAWithTableB();
apply.tableA = currentTableA;
apply.tableBList = currentTableBList;
tableAWithTableBList.add(apply);
}
toBeApplied = true;
currentTableA = tabj.tableA;
currentTableBList = new ArrayList<>();
previousTableAName = currentTableA.nameA;
}
currentTableBList.add(tabj.tableB);
}
if (toBeApplied) {
TableAWithTableB apply = new TableAWithTableB();
apply.tableA = currentTableA;
apply.tableBList = currentTableBList;
tableAWithTableBList.add(apply);
}
}
public static List<TableAWithTableB> getTableAWithTableBList(List<TableAJoinedWithTableB> list) {
return new TableAsWithSelectiveTableB(list).tableAWithTableBList;
}
}
用于:-
for(TableAWithTableB tatab: TableAsWithSelectiveTableB.getTableAWithTableBList(dao.getSelectedViaEmbedded("M"))) {
logTableA(tatab.tableA);
for(TableB tb: tatab.tableBList) {
Log.d(TAG,"\tTableB is " + tb.getName() + " Parent(TableA) ID is " + tb.getTableAMapId());
}
}
它导致:-
2021-06-29 10:00:41.432 D/TABLEINFO: TableA Name = ROW1
2021-06-29 10:00:41.432 D/TABLEINFO: TableB is Z Parent(TableA) ID is 1
2021-06-29 10:00:41.432 D/TABLEINFO: TableB is P Parent(TableA) ID is 1
2021-06-29 10:00:41.432 D/TABLEINFO: TableA Name = ROW2
2021-06-29 10:00:41.432 D/TABLEINFO: TableB is Y Parent(TableA) ID is 2
2021-06-29 10:00:41.433 D/TABLEINFO: TableB is O Parent(TableA) ID is 2
2021-06-29 10:00:41.433 D/TABLEINFO: TableA Name = ROW3
2021-06-29 10:00:41.433 D/TABLEINFO: TableB is X Parent(TableA) ID is 3
2021-06-29 10:00:41.433 D/TABLEINFO: TableB is N Parent(TableA) ID is 3
我有两个 tables table A 和 table B,我正在 android 房间进行内部连接查询(A 内部连接 B),但是我必须从 table B 过滤数据,在 android 房间可以吗?
是的,但您必须了解 Room 的工作原理以及 JOIN 的工作原理(即笛卡尔积,每个与过滤器匹配的组合都会有一行)
通常你会使用 POJO 和 TableA Embedded
(@Embedded
) 和 TableB 作为一个 @Relation
进行组合。例如:-
class TableAWithTableB {
@Embedded
TableA tableA;
@Relation(entity = TableB.class,parentColumn = "tableAId", entityColumn = "tableAMapId")
List<TableB> tableBList;
}
然而,Room 处理 @Relation
的方式是它只从结果中检索 parent,然后继续获取 parent 的所有 children .也就是说,如果过滤器在 child.
如果你想在 children 上应用过滤器,那么你将不会使用 @Relation
但可以 @Embedded
同时使用 parent 和 child 但是然后你得到每个 child 的 parent,所以可以有多个相同的 parent。例如
class TableAJoinedWithTableB {
@Embedded
TableA tableA;
@Embedded
TableB tableB;
}
例子
考虑到这两个实体是:-
@Entity
class TableA {
@PrimaryKey
Long tableAId;
String nameA;
public TableA(){}
@Ignore
public TableA(String name){
this.nameA = name;
}
public Long getTableAId() {
return tableAId;
}
public void setTableAId(Long tableAId) {
this.tableAId = tableAId;
}
public String getName() {
return nameA;
}
public void setName(String name) {
this.nameA = name;
}
}
和:-
@Entity(
foreignKeys = {
@ForeignKey(
entity = TableA.class,
parentColumns = "tableAId",
childColumns = "tableAMapId"
)
}
)
class TableB {
@PrimaryKey
Long tableBId;
@ColumnInfo(index = true)
Long tableAMapId;
String nameB;
public TableB(){}
@Ignore
public TableB(long tableAMapId,String name) {
this.tableAMapId = tableAMapId;
this.nameB = name;
}
public Long getTableBId() {
return tableBId;
}
public void setTableBId(Long tableBId) {
this.tableBId = tableBId;
}
public Long getTableAMapId() {
return tableAMapId;
}
public void setTableAMapId(Long tableAMapId) {
this.tableAMapId = tableAMapId;
}
public String getName() {
return nameB;
}
public void setName(String name) {
this.nameB = name;
}
}
和@Dao,AllDao,是:-
@Dao
interface AllDao {
@Insert long insert(TableA tableA);
@Insert long[] insert(TableA...one_or_more_tableAs);
@Insert long insert(TableB tableB);
@Insert long[] insert(TableB...one_or_moretableBs);
@Query("DELETE FROM tableA") int deleteAllFROMTableA();
@Query("DELETE FROM tableB") int deleteAllFromTableB();
@Query("SELECT * FROM tablea") List<TableA> getALlFromTableA();
@Query("SELECT * FROM tableb") List<TableB> getAllFromTableB();
@Transaction @Query("SELECT tableA.* FROM tablea JOIN tableb ON tableAId = tableAMapId WHERE tableb.nameB >:arg")
List<TableAWithTableB> getSelectedViaRelation(String arg);
@Query("SELECT * FROM tablea JOIN tableb ON tableAId = tableAMapId WHERE tableb.nameB >:arg")
List<TableAJoinedWithTableB> getSelectedViaEmbedded(String arg);
}
@Database class 是 TheDatabase(一个非常标准的)然后使用 :-
public class MainActivity extends AppCompatActivity {
TheDatabase db;
AllDao dao;
private static final String TAG = "TABLEINFO";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = TheDatabase.getInstance(this);
dao = db.getDao();
dao.deleteAllFromTableB();
dao.deleteAllFROMTableA();
long row1Id = dao.insert(new TableA("ROW1"));
long row2Id = dao.insert(new TableA("ROW2"));
long row3Id = dao.insert(new TableA("ROW3"));
long row4Id = dao.insert(new TableA("ROW4"));
dao.insert(new TableB(row1Id,"A"));
dao.insert(new TableB(row1Id,"Z"));
dao.insert(new TableB(row1Id,"P"));
dao.insert(new TableB(row2Id,"B"));
dao.insert(new TableB(row2Id,"Y"));
dao.insert(new TableB(row2Id,"O"));
dao.insert(new TableB(row3Id,"C"));
dao.insert(new TableB(row3Id,"X"));
dao.insert(new TableB(row3Id,"N"));
dao.insert(new TableB(row4Id,"AA"));
dao.insert(new TableB(row4Id,"BB"));
for(TableAWithTableB t: dao.getSelectedViaRelation("M")) {
logTableA(t.tableA);
for(TableB tb: t.tableBList) {
logTableB(tb);
}
}
for (TableAJoinedWithTableB t: dao.getSelectedViaEmbedded("M")) {
Log.d(TAG,"TableA is " + t.tableA.getName() + " TableB is " + t.tableB.getName() + " Parent(TableA) ID is " + t.tableB.getTableAMapId());
}
}
private void logTableA(TableA tableA) {
Log.d(TAG,"TableA Name = " + tableA.getName());
}
private void logTableB(TableB tableB) {
Log.d(TAG,"\tTableB = " + tableB.getName() + " Parent TableA is " + tableB.getTableAMapId());
}
}
结果:-
2021-06-29 07:43:49.134 D/TABLEINFO: TableA Name = ROW1
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = A Parent TableA is 1
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = Z Parent TableA is 1
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = P Parent TableA is 1
2021-06-29 07:43:49.134 D/TABLEINFO: TableA Name = ROW1
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = A Parent TableA is 1
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = Z Parent TableA is 1
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = P Parent TableA is 1
2021-06-29 07:43:49.134 D/TABLEINFO: TableA Name = ROW2
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = B Parent TableA is 2
2021-06-29 07:43:49.134 D/TABLEINFO: TableB = Y Parent TableA is 2
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = O Parent TableA is 2
2021-06-29 07:43:49.135 D/TABLEINFO: TableA Name = ROW2
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = B Parent TableA is 2
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = Y Parent TableA is 2
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = O Parent TableA is 2
2021-06-29 07:43:49.135 D/TABLEINFO: TableA Name = ROW3
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = C Parent TableA is 3
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = X Parent TableA is 3
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = N Parent TableA is 3
2021-06-29 07:43:49.135 D/TABLEINFO: TableA Name = ROW3
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = C Parent TableA is 3
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = X Parent TableA is 3
2021-06-29 07:43:49.135 D/TABLEINFO: TableB = N Parent TableA is 3
2021-06-29 07:43:49.140 D/TABLEINFO: TableA is ROW1 TableB is Z Parent(TableA) ID is 1
2021-06-29 07:43:49.140 D/TABLEINFO: TableA is ROW1 TableB is P Parent(TableA) ID is 1
2021-06-29 07:43:49.140 D/TABLEINFO: TableA is ROW2 TableB is Y Parent(TableA) ID is 2
2021-06-29 07:43:49.140 D/TABLEINFO: TableA is ROW2 TableB is O Parent(TableA) ID is 2
2021-06-29 07:43:49.140 D/TABLEINFO: TableA is ROW3 TableB is X Parent(TableA) ID is 3
2021-06-29 07:43:49.140 D/TABLEINFO: TableA is ROW3 TableB is N Parent(TableA) ID is 3
因此 ROW4 不存在,由于过滤,在任何一种方法中 BUT:-
with @Relation
for TableB,结果是完整的Table A objects忽略了关于children的WHERE子句。
当对 TableB 使用 @Embedded
时,将应用过滤器,但是 parent 会得到多行(就像没有空间一样)。
额外
如果您想部分构建 TableA objects,即使用选择性 children,那么您必须完成基础工作(就像您必须使用原生 SQLite)。您可以根据 getSelectedViaEmbedded 的结果构建它们,方法是将相同的 TableA 合并到任一 POJO classes 中(如果不是,注释将被忽略按房间建造)。例如考虑:-
class TableAsWithSelectiveTableB {
private ArrayList<TableAWithTableB> tableAWithTableBList = new ArrayList<>();
private TableAsWithSelectiveTableB(List<TableAJoinedWithTableB> baselist) {
String previousTableAName = "";
TableA currentTableA = null;
ArrayList<TableB> currentTableBList = new ArrayList<>();
boolean toBeApplied = false;
for (TableAJoinedWithTableB tabj: baselist) {
if (!tabj.tableA.nameA.equals(previousTableAName)) {
if (toBeApplied) {
TableAWithTableB apply = new TableAWithTableB();
apply.tableA = currentTableA;
apply.tableBList = currentTableBList;
tableAWithTableBList.add(apply);
}
toBeApplied = true;
currentTableA = tabj.tableA;
currentTableBList = new ArrayList<>();
previousTableAName = currentTableA.nameA;
}
currentTableBList.add(tabj.tableB);
}
if (toBeApplied) {
TableAWithTableB apply = new TableAWithTableB();
apply.tableA = currentTableA;
apply.tableBList = currentTableBList;
tableAWithTableBList.add(apply);
}
}
public static List<TableAWithTableB> getTableAWithTableBList(List<TableAJoinedWithTableB> list) {
return new TableAsWithSelectiveTableB(list).tableAWithTableBList;
}
}
用于:-
for(TableAWithTableB tatab: TableAsWithSelectiveTableB.getTableAWithTableBList(dao.getSelectedViaEmbedded("M"))) {
logTableA(tatab.tableA);
for(TableB tb: tatab.tableBList) {
Log.d(TAG,"\tTableB is " + tb.getName() + " Parent(TableA) ID is " + tb.getTableAMapId());
}
}
它导致:-
2021-06-29 10:00:41.432 D/TABLEINFO: TableA Name = ROW1
2021-06-29 10:00:41.432 D/TABLEINFO: TableB is Z Parent(TableA) ID is 1
2021-06-29 10:00:41.432 D/TABLEINFO: TableB is P Parent(TableA) ID is 1
2021-06-29 10:00:41.432 D/TABLEINFO: TableA Name = ROW2
2021-06-29 10:00:41.432 D/TABLEINFO: TableB is Y Parent(TableA) ID is 2
2021-06-29 10:00:41.433 D/TABLEINFO: TableB is O Parent(TableA) ID is 2
2021-06-29 10:00:41.433 D/TABLEINFO: TableA Name = ROW3
2021-06-29 10:00:41.433 D/TABLEINFO: TableB is X Parent(TableA) ID is 3
2021-06-29 10:00:41.433 D/TABLEINFO: TableB is N Parent(TableA) ID is 3