使用 orderBy 从 Android 房间获取嵌入关系定义的 table
use orderBy to get embedded relation-defined table from Android Room
在 Android 房间查询此交易:
@Transaction
@Query("SELECT * FROM TPAGroup WHERE zuid=:zuid ORDER BY `index`")
fun getGroupWithSecretsForZuid(zuid: String): List<TPAGroupWithSecrets>
这是我的数据 class :
data class TPAGroupWithSecrets(
@Embedded val group: TPAGroup,
@Relation(
parentColumn = "groupId",
entityColumn = "groupId"
)
var secrets: MutableList<TPASecrets>
)
我以正确的顺序获得了 TPAGroup,但尚未订购 TPASecrets!我怎样才能按正确的顺序排列它们,按它们的索引(这是两个表共有的列)排序?
当使用 @Relation
时,Room 获取相关对象,如您所见,没有任何特定顺序(顺序可能按主键排序,但这取决于 SQLite 的查询优化器)。
如果您需要订购它们,您可以
- 对返回的集合进行排序或
- 您可以有效地override/bypass Room 实现的@Relation 处理。
- 使用单个查询进行相应排序,然后从笛卡尔积构建结果(部分示例见底部)
这是 2 的工作示例
TPAGroup(编)
@Entity
data class TPAGroup(
@PrimaryKey
val groupId: Long? = null,
val zuid: String,
val index: Long,
)
TPASecrets(编造)
@Entity
data class TPASecrets(
@PrimaryKey
val secretId: Long? = null,
val groupId: Long,
val index: Long
)
TPAGroupWithSecrets(未更改)
data class TPAGroupWithSecrets(
@Embedded val group: TPAGroup,
@Relation(
parentColumn = "groupId",
entityColumn = "groupId"
)
var secrets: MutableList<TPASecrets>
)
@Dao 注释class
@Dao
interface AllDAO {
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(tpaGroup: TPAGroup): Long
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(tpaSecrets: TPASecrets): Long
@Query("SELECT * FROM TPASecrets WHERE groupId=:groupId ORDER BY `index`;")
fun getRelatedSecrets(groupId: Long): MutableList<TPASecrets>
@Query("SELECT * FROM TPAGroup WHERE zuid=:zuid ORDER BY `index`;")
fun getGroupsForZuid(zuid: String): MutableList<TPAGroup>
@Transaction
@Query("")
fun getGroupWithSecretsForZuid(zuid: String): List<TPAGroupWithSecrets> {
val rv = ArrayList<TPAGroupWithSecrets>()
for(t in getGroupsForZuid(zuid)) {
rv.add(TPAGroupWithSecrets(t,getRelatedSecrets(t.groupId!!)))
}
// rv.sortBy { .... }
return rv
}
}
- 注意@Query,尤其是最后一个绕过 Rooms @Relation 处理的(即 TPAGroupWithSecrets 是在房间外构建的)
@Database 注释 class 将所有 Room 内容联系在一起 TheDatabase
@Database(entities = [TPAGroup::class,TPASecrets::class], version = 1, exportSchema = false)
abstract class TheDatabase: RoomDatabase() {
abstract fun getAllDAO(): AllDAO
companion object {
private var instance: TheDatabase? = null
fun getInstance(context: Context): TheDatabase {
if (instance == null) {
instance = Room.databaseBuilder(context,TheDatabase::class.java,"the_database.db")
.allowMainThreadQueries()
.build()
}
return instance as TheDatabase
}
}
}
- 为了方便和简洁,在主线程上设置为 运行
终于在 Activity 中付诸行动了:-
class MainActivity : AppCompatActivity() {
lateinit var db: TheDatabase
lateinit var dao: AllDAO
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = TheDatabase.getInstance(this)
dao = db.getAllDAO()
dao.insert(TPAGroup(groupId = 1,zuid = "Group1", index = 10))
dao.insert(TPAGroup(groupId = 2, zuid = "Group1", index = 9))
dao.insert(TPAGroup(groupId = 3, zuid = "Group1", index = 11))
dao.insert(TPASecrets(1000,1,5))
dao.insert(TPASecrets(1010,groupId = 1, index = 4))
dao.insert(TPASecrets(1020,1,3))
dao.insert(TPASecrets(2000,2,5))
dao.insert(TPASecrets(2010,2,6))
dao.insert(TPASecrets(2020,2,7))
dao.insert(TPASecrets(2030,2,1))
dao.insert(TPASecrets(2040,2,2))
dao.insert(TPASecrets(2050,2,3))
dao.insert(TPASecrets(3000,3,1))
dao.insert(TPASecrets(3010,3,0))
for(tgws in dao.getGroupWithSecretsForZuid("Group1")) {
Log.d("DBINFO","TPAGroup is ${tgws.group.groupId} Index is ${tgws.group.index}. It has ${tgws.secrets.size} Secrets, they are :-")
for (s in tgws.secrets) {
Log.d("DBINFO","\tSecret is ${s.secretId} Index is ${s.index}")
}
}
}
}
输出到日志的结果(注意为了演示排序特意插入了数据):-
2022-04-13 21:37:29.220 D/DBINFO: TPAGroup is 2 Index is 9. It has 6 Secrets, they are :-
2022-04-13 21:37:29.220 D/DBINFO: Secret is 2030 Index is 1
2022-04-13 21:37:29.220 D/DBINFO: Secret is 2040 Index is 2
2022-04-13 21:37:29.220 D/DBINFO: Secret is 2050 Index is 3
2022-04-13 21:37:29.220 D/DBINFO: Secret is 2000 Index is 5
2022-04-13 21:37:29.220 D/DBINFO: Secret is 2010 Index is 6
2022-04-13 21:37:29.220 D/DBINFO: Secret is 2020 Index is 7
2022-04-13 21:37:29.221 D/DBINFO: TPAGroup is 1 Index is 10. It has 3 Secrets, they are :-
2022-04-13 21:37:29.221 D/DBINFO: Secret is 1020 Index is 3
2022-04-13 21:37:29.221 D/DBINFO: Secret is 1010 Index is 4
2022-04-13 21:37:29.221 D/DBINFO: Secret is 1000 Index is 5
2022-04-13 21:37:29.221 D/DBINFO: TPAGroup is 3 Index is 11. It has 2 Secrets, they are :-
2022-04-13 21:37:29.221 D/DBINFO: Secret is 3010 Index is 0
2022-04-13 21:37:29.221 D/DBINFO: Secret is 3000 Index is 1
- 所以 TPAGroups 根据索引值排序(2 索引 9 是第一个,3 索引 10 第二和 3 索引 11 第三)
- 你可以很容易地看到 Secrets 是根据它们的索引而不是它们的主键 secrteId 排序的
选项 3 的部分示例
查询如
SELECT * FROM TPAGroup JOIN TPASecrets ON TPASecrets.groupid = TPAGroup.groupid ORDER BY TPAGroup.`index` ASC, TPASecrets.`index`;
将产生数据(使用工作示例加载的数据):-
然后您需要有一个 POJO 来接收数据。但是,重复的列名 index 和 groupid 存在问题,因此查询更加复杂,需要别名 (AS),例如你可以使用
SELECT TPAGroup.*, TPASecrets.secretId, TPASecrets.`index` AS secretIndex FROM TPAGroup JOIN TPASecrets ON TPASecrets.groupid = TPAGroup.groupid ORDER BY TPAGroup.`index` ASC, TPASecrets.`index`;
因此从 TPASecrets 中删除重复的 groupid(在两者中始终具有相同的值)并且 TPASecrets 列是 aliased/renamed 作为 secretsIndex。显然 POJO 必须满足这一点。
然后您必须通过遍历结果来使用它的 TPASecrets 构建每个 TPAGroup。
不是 done/shown,因为大多数人倾向于选择选项 1 或 2,而倾向于选择选项 3。但是,选项 3 可能更有效,因为只有一个查询(不需要 @交易)。
在 Android 房间查询此交易:
@Transaction
@Query("SELECT * FROM TPAGroup WHERE zuid=:zuid ORDER BY `index`")
fun getGroupWithSecretsForZuid(zuid: String): List<TPAGroupWithSecrets>
这是我的数据 class :
data class TPAGroupWithSecrets(
@Embedded val group: TPAGroup,
@Relation(
parentColumn = "groupId",
entityColumn = "groupId"
)
var secrets: MutableList<TPASecrets>
)
我以正确的顺序获得了 TPAGroup,但尚未订购 TPASecrets!我怎样才能按正确的顺序排列它们,按它们的索引(这是两个表共有的列)排序?
当使用 @Relation
时,Room 获取相关对象,如您所见,没有任何特定顺序(顺序可能按主键排序,但这取决于 SQLite 的查询优化器)。
如果您需要订购它们,您可以
- 对返回的集合进行排序或
- 您可以有效地override/bypass Room 实现的@Relation 处理。
- 使用单个查询进行相应排序,然后从笛卡尔积构建结果(部分示例见底部)
这是 2 的工作示例
TPAGroup(编)
@Entity
data class TPAGroup(
@PrimaryKey
val groupId: Long? = null,
val zuid: String,
val index: Long,
)
TPASecrets(编造)
@Entity
data class TPASecrets(
@PrimaryKey
val secretId: Long? = null,
val groupId: Long,
val index: Long
)
TPAGroupWithSecrets(未更改)
data class TPAGroupWithSecrets(
@Embedded val group: TPAGroup,
@Relation(
parentColumn = "groupId",
entityColumn = "groupId"
)
var secrets: MutableList<TPASecrets>
)
@Dao 注释class
@Dao
interface AllDAO {
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(tpaGroup: TPAGroup): Long
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(tpaSecrets: TPASecrets): Long
@Query("SELECT * FROM TPASecrets WHERE groupId=:groupId ORDER BY `index`;")
fun getRelatedSecrets(groupId: Long): MutableList<TPASecrets>
@Query("SELECT * FROM TPAGroup WHERE zuid=:zuid ORDER BY `index`;")
fun getGroupsForZuid(zuid: String): MutableList<TPAGroup>
@Transaction
@Query("")
fun getGroupWithSecretsForZuid(zuid: String): List<TPAGroupWithSecrets> {
val rv = ArrayList<TPAGroupWithSecrets>()
for(t in getGroupsForZuid(zuid)) {
rv.add(TPAGroupWithSecrets(t,getRelatedSecrets(t.groupId!!)))
}
// rv.sortBy { .... }
return rv
}
}
- 注意@Query,尤其是最后一个绕过 Rooms @Relation 处理的(即 TPAGroupWithSecrets 是在房间外构建的)
@Database 注释 class 将所有 Room 内容联系在一起 TheDatabase
@Database(entities = [TPAGroup::class,TPASecrets::class], version = 1, exportSchema = false)
abstract class TheDatabase: RoomDatabase() {
abstract fun getAllDAO(): AllDAO
companion object {
private var instance: TheDatabase? = null
fun getInstance(context: Context): TheDatabase {
if (instance == null) {
instance = Room.databaseBuilder(context,TheDatabase::class.java,"the_database.db")
.allowMainThreadQueries()
.build()
}
return instance as TheDatabase
}
}
}
- 为了方便和简洁,在主线程上设置为 运行
终于在 Activity 中付诸行动了:-
class MainActivity : AppCompatActivity() {
lateinit var db: TheDatabase
lateinit var dao: AllDAO
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = TheDatabase.getInstance(this)
dao = db.getAllDAO()
dao.insert(TPAGroup(groupId = 1,zuid = "Group1", index = 10))
dao.insert(TPAGroup(groupId = 2, zuid = "Group1", index = 9))
dao.insert(TPAGroup(groupId = 3, zuid = "Group1", index = 11))
dao.insert(TPASecrets(1000,1,5))
dao.insert(TPASecrets(1010,groupId = 1, index = 4))
dao.insert(TPASecrets(1020,1,3))
dao.insert(TPASecrets(2000,2,5))
dao.insert(TPASecrets(2010,2,6))
dao.insert(TPASecrets(2020,2,7))
dao.insert(TPASecrets(2030,2,1))
dao.insert(TPASecrets(2040,2,2))
dao.insert(TPASecrets(2050,2,3))
dao.insert(TPASecrets(3000,3,1))
dao.insert(TPASecrets(3010,3,0))
for(tgws in dao.getGroupWithSecretsForZuid("Group1")) {
Log.d("DBINFO","TPAGroup is ${tgws.group.groupId} Index is ${tgws.group.index}. It has ${tgws.secrets.size} Secrets, they are :-")
for (s in tgws.secrets) {
Log.d("DBINFO","\tSecret is ${s.secretId} Index is ${s.index}")
}
}
}
}
输出到日志的结果(注意为了演示排序特意插入了数据):-
2022-04-13 21:37:29.220 D/DBINFO: TPAGroup is 2 Index is 9. It has 6 Secrets, they are :-
2022-04-13 21:37:29.220 D/DBINFO: Secret is 2030 Index is 1
2022-04-13 21:37:29.220 D/DBINFO: Secret is 2040 Index is 2
2022-04-13 21:37:29.220 D/DBINFO: Secret is 2050 Index is 3
2022-04-13 21:37:29.220 D/DBINFO: Secret is 2000 Index is 5
2022-04-13 21:37:29.220 D/DBINFO: Secret is 2010 Index is 6
2022-04-13 21:37:29.220 D/DBINFO: Secret is 2020 Index is 7
2022-04-13 21:37:29.221 D/DBINFO: TPAGroup is 1 Index is 10. It has 3 Secrets, they are :-
2022-04-13 21:37:29.221 D/DBINFO: Secret is 1020 Index is 3
2022-04-13 21:37:29.221 D/DBINFO: Secret is 1010 Index is 4
2022-04-13 21:37:29.221 D/DBINFO: Secret is 1000 Index is 5
2022-04-13 21:37:29.221 D/DBINFO: TPAGroup is 3 Index is 11. It has 2 Secrets, they are :-
2022-04-13 21:37:29.221 D/DBINFO: Secret is 3010 Index is 0
2022-04-13 21:37:29.221 D/DBINFO: Secret is 3000 Index is 1
- 所以 TPAGroups 根据索引值排序(2 索引 9 是第一个,3 索引 10 第二和 3 索引 11 第三)
- 你可以很容易地看到 Secrets 是根据它们的索引而不是它们的主键 secrteId 排序的
选项 3 的部分示例
查询如
SELECT * FROM TPAGroup JOIN TPASecrets ON TPASecrets.groupid = TPAGroup.groupid ORDER BY TPAGroup.`index` ASC, TPASecrets.`index`;
将产生数据(使用工作示例加载的数据):-
然后您需要有一个 POJO 来接收数据。但是,重复的列名 index 和 groupid 存在问题,因此查询更加复杂,需要别名 (AS),例如你可以使用
SELECT TPAGroup.*, TPASecrets.secretId, TPASecrets.`index` AS secretIndex FROM TPAGroup JOIN TPASecrets ON TPASecrets.groupid = TPAGroup.groupid ORDER BY TPAGroup.`index` ASC, TPASecrets.`index`;
因此从 TPASecrets 中删除重复的 groupid(在两者中始终具有相同的值)并且 TPASecrets 列是 aliased/renamed 作为 secretsIndex。显然 POJO 必须满足这一点。
然后您必须通过遍历结果来使用它的 TPASecrets 构建每个 TPAGroup。
不是 done/shown,因为大多数人倾向于选择选项 1 或 2,而倾向于选择选项 3。但是,选项 3 可能更有效,因为只有一个查询(不需要 @交易)。