首页 > 解决方案 > 如何在android房间加入查询中的内表中进行过滤

问题描述

我有两个表 A 表和 B 表,我在 android 房间进行内连接查询(A 内连接 B),但我必须从表 B 中过滤数据,这在 android 房间中可能吗?

标签: androidandroid-room

解决方案


是的,但是您必须了解 Room 的工作原理以及 JOIN 的工作原理(即笛卡尔积,每个与过滤器匹配的组合都会有一行)

通常,您会使用带有TableA Embedded ( @Embedded)的 POJO 和TableB作为@Relation组合。例如:-

class TableAWithTableB {
    @Embedded
    TableA tableA;
    @Relation(entity = TableB.class,parentColumn = "tableAId", entityColumn = "tableAMapId")
    List<TableB> tableBList;
}

但是,Room 处理的方式@Relation是它只从结果中检索父级,然后继续获取父级的所有子级。也就是说,如果过滤器在孩子身上,它会构建一个忽略过滤器的完整对象。

如果您希望将过滤器应用于孩子,那么您不会使用@Relation但可以@Embedded同时使用父母和孩子,但是您可以获得每个孩子的父母,因此可以有多个相同的父母。例如

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 类是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不存在,由于过滤,在任何一种方法中,但是:-

对于@RelationTableB,结果是完整的 Table A 对象,忽略了关于子项的 WHERE 子句。

@Embedded用于 TableB 时,将应用过滤器,但您会为父级获得多行(就像没有空间一样)。

额外的

如果您想获得部分构建的 TableA 对象,即具有选择性子对象,那么您必须完成基础工作(就像使用原生 SQLite 一样)。您可以通过将相同的 TableA 合并到任何一个 POJO 类中来基于getSelectedViaEmbedded的结果构建它们(如果不是由房间构建的注释将被忽略)。例如考虑: -

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

推荐阅读