如何在 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