有没有办法检索仅包含特定日期范围内的孩子的列表?
没那么容易。@Relation 的工作原理是根据第二个查询获取父级的所有子级(因此推荐使用 @Transaction)。过滤仅适用于父项的选择。
问题是,如果你使用类似的东西: -
SELECT * FROM parent JOIN child ON child.Id = parent.elementId WHERE date BETWEEN fromDate and toDate;
返回的是一个列表,其中每行包含父项和单个子项。要提取父级和所有过滤的子级,需要处理该列表以挑出父级及其子级。
根据可用的代码,这是一个示例。
一个例外是 Id 列,它通常是子级的 ID,因此添加了一个 parentId 列来保存父级的 ID。
另一个例外是,为了方便/简洁,日期只是一个字符串 (TEXT),而不是需要 @TypeConverter 的 Instant。
第三个例外是使用了伴生对象(如将在适当的时候显示的那样)。
首先新建一个POJO,Filter用于提取过滤后的列表(父子各一行)
data class Filter(
@Embedded
val parent: Parent,
@Embedded
val child: Child
)
接下来是一个合适的 Dao getFiltered查询(几乎和上面一样):-
@Query("SELECT * FROM parent JOIN child ON child.parentId = parent.elementId WHERE date BETWEEN :fromDate AND :toDate")
abstract fun getFiltered(fromDate: String, toDate:String): List<Filter>
- 请注意,这将返回Filter的列表而不是组合的列表
最后是Child和伴随对象,以方便从过滤器列表中构建组合的列表:-
@Entity
data class Child(
@PrimaryKey
var id: Long? = null,
var parentId: Long,
@NotNull
var childName: String,
var date: String
) {
companion object {
fun buildParentsWithChildren(filter: List<Filter>): List<Combined> {
var rv: ArrayList<Combined> = arrayListOf()
if (filter.size < 1) return rv
for (f: Filter in filter) {
addChild(rv, getOrAddParent(rv, f), f)
}
return rv
}
private fun getOrAddParent(built: ArrayList<Combined>, f: Filter): Int {
for (i in 0..(built.size-1)) {
if (built.get(i).parent.parentName == f.parent.parentName) {
return i
}
}
var newCombined: Combined = Combined(f.parent, emptyList())
built.add(newCombined)
return built.size - 1
}
private fun addChild(built: ArrayList<Combined>, parentIx: Int, f: Filter) {
var currentChildren: ArrayList<Child> = arrayListOf<Child>()
currentChildren.addAll(built.get(parentIx).children)
currentChildren.add(f.child)
built[parentIx] = Combined(parent = built.get(parentIx).parent, currentChildren)
}
}
}
例子
这是使用上述内容的示例。
首先,它构建了一些数据,3 个父母 5 个孩子(第一个父母 3 个,第二个父母 2 个,第三个父母 0 个):-

和

然后它使用查询来提取一些数据并将其转换为列表。然后遍历列表输出到日志。
这是来自 Activity 的代码:-
db = TheDatabase.getInstance(this)
dao = db.getAllDao()
var p1 = dao.insert(Parent(parentName = "Parent1"))
var p2 = dao.insert(Parent(parentName = "Parent2"))
var p3 = dao.insert(Parent(parentName = "Parent3"))
dao.insert(Child(parentId = p1,childName = "Child1",date = "2000-01-01"))
dao.insert(Child(parentId = p1,childName = "Child2",date = "2003-01-01"))
dao.insert(Child(parentId = p1,childName = "Child3",date = "2005-01-01"))
dao.insert(Child(parentId = p2,childName = "Child4",date = "2006-01-01"))
dao.insert(Child(parentId = p2,childName = "Child5",date = "2007-01-01"))
for(cmbnd: Combined in Child.buildParentsWithChildren(dao.getFiltered("2004-12-31","2010-01-01"))) {
Log.d("DBINFO","Parent is ${cmbnd.parent.parentName}")
for(c: Child in cmbnd.children)
Log.d("DBINFO","Child is ${c.childName} date is ${c.date}")
}
结果: -
2021-08-02 08:38:50.426 D/DBINFO: Parent is Parent1
2021-08-02 08:38:50.426 D/DBINFO: Child is Child3 date is 2005-01-01
2021-08-02 08:38:50.426 D/DBINFO: Parent is Parent2
2021-08-02 08:38:50.427 D/DBINFO: Child is Child4 date is 2006-01-01
2021-08-02 08:38:50.427 D/DBINFO: Child is Child5 date is 2007-01-01
即第一个父母的 3 个孩子中只有 1 个的日期在 2005 年和 2009 年之间。但是,第二个父母的两个孩子都适合日期范围。第三个父母什么都没有。