如何在 Room 中处理这种嵌套关系?
How to work this nested relationship in Room?
我需要一点帮助。
我已经创建了所有的表,我可以创建一个关系来检索应用程序,但我不知道如何检索带有模型的汽车品牌列表。
@Entity(tableName = "application_table", indices = [Index(value = ["name"], unique = true)])
data class ApplicationItem(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id") val id: Int? = 0,
@ColumnInfo(name = "name") val name: String
)
data class ApplicationWithBrandAndModel(
@Embedded val application: ApplicationItem,
@Relation(
entity = BrandOfVehicleItem::class,
parentColumn = "userId",
entityColumn = "brandId"
)
val brands: List<BrandWithModel>
)
data class BrandWithModel(
@Embedded val brand: BrandOfVehicleItem,
@Relation(
parentColumn = "path",
entityColumn = "brandCreatorId"
)
val models: List<ModelOfVehicleItem>
)
简而言之,您需要使用 AppBrandCrossRef table 来引用(关联)ApplicationItem 与 Brand 以获取 BrandWithModel 的列表。
Room 使用的关键字是 associateBy,因此在 @Relation
中您需要使用 [=21= 指定关联] 参数。
associateBy
参数本身带有一个 Junction
参数,您可以在其中定义交叉引用 table 和相应的列。
所以我相信你想要:-
data class ApplicationWithBrandAndModel(
@Embedded val application: ApplicationItem,
/*
@Relation(
entity = Brand::class,
parentColumn = "userId", ???????
entityColumn = "brandId"
)
*/
@Relation(
entity = Brand::class,
parentColumn = "id",
entityColumn = "id",
associateBy = Junction(
value = ApplicationBrandCrossRef::class,
parentColumn = "appId", // column in cross ref table that references the parent (application)
entityColumn = "brandId" // column in cross ref table that references the child (brand)
)
)
val brands: List<BrandWithModel>
)
下面是一个工作示例。
- 请注意,已进行更改,因为您有 long 的引用字符串,并且您还有(如上文注释)用户 ID,这不在您的图表中。
所以用来演示的实体是:-
型号
@Entity(
indices = [Index("brandCreatorId", unique = false)],
foreignKeys = [
ForeignKey(
entity = Brand::class,
parentColumns = ["id"],
childColumns = ["brandCreatorId"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE)
]
)
data class Model(
@PrimaryKey
val id: Long? = null,
val path: String,
val code: String,
val value: String,
val brandCreatorId: Long
)
品牌
@Entity(tableName = "brand_table")
data class Brand(
@PrimaryKey
val id: Long? = null,
val path: String,
val code: String,
val value: String
)
ApplicationItem
@Entity(tableName = "application_table", indices = [Index(value = ["name"], unique = true)])
data class ApplicationItem(
@PrimaryKey
@ColumnInfo(name = "id") val id: Long? = null,
@ColumnInfo(name = "name") val name: String
)
ApplicationBrandCrossRef
@Entity(
primaryKeys = ["appId","brandId"],
indices = [ Index(value = ["brandId"])],
foreignKeys = [
ForeignKey(
entity = ApplicationItem::class,
parentColumns = ["id"],
childColumns = ["appId"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE),
ForeignKey(
entity = Brand::class,
parentColumns = ["id"],
childColumns = ["brandId"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
)
]
)
data class ApplicationBrandCrossRef(
val appId: Long,
val brandId: Long
)
BrandWithModel 是
data class BrandWithModel(
@Embedded val brand: Brand,
@Relation(
parentColumn = "id",
entityColumn = "brandCreatorId"
)
val models: List<Model>
)
ApplicationWithBrandAndModel 是
data class ApplicationWithBrandAndModel(
@Embedded val application: ApplicationItem,
/*
@Relation(
entity = Brand::class,
parentColumn = "userId", ???????
entityColumn = "brandId"
)
*/
@Relation(
entity = Brand::class,
parentColumn = "id",
entityColumn = "id",
associateBy = Junction(
value = ApplicationBrandCrossRef::class,
parentColumn = "appId", // column in cross ref table that references the parent (application)
entityColumn = "brandId" // column in cross ref table that references the child (brand)
)
)
val brands: List<BrandWithModel>
)
Dao 在 AllDao 中是:-
@Dao
abstract class AllDao {
@Insert
abstract fun insert(brand: Brand): Long
@Insert
abstract fun insert(model: Model): Long
@Insert
abstract fun insert(applicationItem: ApplicationItem): Long
@Insert
abstract fun insert(applicationBrandCrossRef: ApplicationBrandCrossRef)
@Query("SELECT * FROM application_table")
@Transaction
abstract fun getApplicationItemWithBrandAndTheModels(): List<ApplicationWithBrandAndModel>
}
以下是用来测试的:-
db = TheDatabase.getInstance(this)
dao = db.getHymnDao()
allDao = db.getAllDao()
var ai1 = allDao.insert(ApplicationItem(name = "A1"))
var ai2 = allDao.insert(ApplicationItem(name = "A2"))
var ai3 = allDao.insert(ApplicationItem(name = "A3"))
var ai4 = allDao.insert(ApplicationItem(name = "A4"))
var b1 = allDao.insert(Brand(path = "patha", code = "codea", value = "vala"))
var b2 = allDao.insert(Brand(path = "pathb",code = "codeb",value = "valb"))
var b3 = allDao.insert(Brand(path = "pathc",code = "codec",value = "valc"))
allDao.insert(Model(path = "ma",code = "ma",value = "ma",brandCreatorId = b1))
allDao.insert(Model(path = "mb", code = "mb", value = "mb", brandCreatorId = b1))
allDao.insert(Model(path = "mc",code = "mc", value = "mc",brandCreatorId = b2))
allDao.insert(Model(path = "md",code = "md", value = "md", brandCreatorId = b2))
allDao.insert(Model(path = "me", code = "me", value = "me", brandCreatorId = b2))
allDao.insert(ApplicationBrandCrossRef(ai1,b2))
allDao.insert(ApplicationBrandCrossRef(ai1,b3))
allDao.insert(ApplicationBrandCrossRef(ai2,b1))
allDao.insert(ApplicationBrandCrossRef(ai3,b1))
allDao.insert(ApplicationBrandCrossRef(ai3,b2))
allDao.insert(ApplicationBrandCrossRef(ai3,b3))
for(a: ApplicationWithBrandAndModel in allDao.getApplicationItemWithBrandAndTheModels()) {
Log.d(TAG,"AppItem is ${a.application.name}")
for(b: BrandWithModel in a.brands) {
Log.d(TAG,"\tBrand is ${b.brand.code}")
for(m: Model in b.models) {
Log.d(TAG,"\t\tModel is ${m.code}")
}
}
}
结果输出到日志:-
D/APPINFO: AppItem is A1
D/APPINFO: Brand is codeb
D/APPINFO: Model is mc
D/APPINFO: Model is md
D/APPINFO: Model is me
D/APPINFO: Brand is codec
D/APPINFO: AppItem is A2
D/APPINFO: Brand is codea
D/APPINFO: Model is ma
D/APPINFO: Model is mb
D/APPINFO: AppItem is A3
D/APPINFO: Brand is codea
D/APPINFO: Model is ma
D/APPINFO: Model is mb
D/APPINFO: Brand is codeb
D/APPINFO: Model is mc
D/APPINFO: Model is md
D/APPINFO: Model is me
D/APPINFO: Brand is codec
D/APPINFO: AppItem is A4
- 即预期结果
我需要一点帮助。 我已经创建了所有的表,我可以创建一个关系来检索应用程序,但我不知道如何检索带有模型的汽车品牌列表。
@Entity(tableName = "application_table", indices = [Index(value = ["name"], unique = true)])
data class ApplicationItem(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id") val id: Int? = 0,
@ColumnInfo(name = "name") val name: String
)
data class ApplicationWithBrandAndModel(
@Embedded val application: ApplicationItem,
@Relation(
entity = BrandOfVehicleItem::class,
parentColumn = "userId",
entityColumn = "brandId"
)
val brands: List<BrandWithModel>
)
data class BrandWithModel(
@Embedded val brand: BrandOfVehicleItem,
@Relation(
parentColumn = "path",
entityColumn = "brandCreatorId"
)
val models: List<ModelOfVehicleItem>
)
简而言之,您需要使用 AppBrandCrossRef table 来引用(关联)ApplicationItem 与 Brand 以获取 BrandWithModel 的列表。
Room 使用的关键字是 associateBy,因此在 @Relation
中您需要使用 [=21= 指定关联] 参数。
associateBy
参数本身带有一个 Junction
参数,您可以在其中定义交叉引用 table 和相应的列。
所以我相信你想要:-
data class ApplicationWithBrandAndModel(
@Embedded val application: ApplicationItem,
/*
@Relation(
entity = Brand::class,
parentColumn = "userId", ???????
entityColumn = "brandId"
)
*/
@Relation(
entity = Brand::class,
parentColumn = "id",
entityColumn = "id",
associateBy = Junction(
value = ApplicationBrandCrossRef::class,
parentColumn = "appId", // column in cross ref table that references the parent (application)
entityColumn = "brandId" // column in cross ref table that references the child (brand)
)
)
val brands: List<BrandWithModel>
)
下面是一个工作示例。
- 请注意,已进行更改,因为您有 long 的引用字符串,并且您还有(如上文注释)用户 ID,这不在您的图表中。
所以用来演示的实体是:-
型号
@Entity(
indices = [Index("brandCreatorId", unique = false)],
foreignKeys = [
ForeignKey(
entity = Brand::class,
parentColumns = ["id"],
childColumns = ["brandCreatorId"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE)
]
)
data class Model(
@PrimaryKey
val id: Long? = null,
val path: String,
val code: String,
val value: String,
val brandCreatorId: Long
)
品牌
@Entity(tableName = "brand_table")
data class Brand(
@PrimaryKey
val id: Long? = null,
val path: String,
val code: String,
val value: String
)
ApplicationItem
@Entity(tableName = "application_table", indices = [Index(value = ["name"], unique = true)])
data class ApplicationItem(
@PrimaryKey
@ColumnInfo(name = "id") val id: Long? = null,
@ColumnInfo(name = "name") val name: String
)
ApplicationBrandCrossRef
@Entity(
primaryKeys = ["appId","brandId"],
indices = [ Index(value = ["brandId"])],
foreignKeys = [
ForeignKey(
entity = ApplicationItem::class,
parentColumns = ["id"],
childColumns = ["appId"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE),
ForeignKey(
entity = Brand::class,
parentColumns = ["id"],
childColumns = ["brandId"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
)
]
)
data class ApplicationBrandCrossRef(
val appId: Long,
val brandId: Long
)
BrandWithModel 是
data class BrandWithModel(
@Embedded val brand: Brand,
@Relation(
parentColumn = "id",
entityColumn = "brandCreatorId"
)
val models: List<Model>
)
ApplicationWithBrandAndModel 是
data class ApplicationWithBrandAndModel(
@Embedded val application: ApplicationItem,
/*
@Relation(
entity = Brand::class,
parentColumn = "userId", ???????
entityColumn = "brandId"
)
*/
@Relation(
entity = Brand::class,
parentColumn = "id",
entityColumn = "id",
associateBy = Junction(
value = ApplicationBrandCrossRef::class,
parentColumn = "appId", // column in cross ref table that references the parent (application)
entityColumn = "brandId" // column in cross ref table that references the child (brand)
)
)
val brands: List<BrandWithModel>
)
Dao 在 AllDao 中是:-
@Dao
abstract class AllDao {
@Insert
abstract fun insert(brand: Brand): Long
@Insert
abstract fun insert(model: Model): Long
@Insert
abstract fun insert(applicationItem: ApplicationItem): Long
@Insert
abstract fun insert(applicationBrandCrossRef: ApplicationBrandCrossRef)
@Query("SELECT * FROM application_table")
@Transaction
abstract fun getApplicationItemWithBrandAndTheModels(): List<ApplicationWithBrandAndModel>
}
以下是用来测试的:-
db = TheDatabase.getInstance(this)
dao = db.getHymnDao()
allDao = db.getAllDao()
var ai1 = allDao.insert(ApplicationItem(name = "A1"))
var ai2 = allDao.insert(ApplicationItem(name = "A2"))
var ai3 = allDao.insert(ApplicationItem(name = "A3"))
var ai4 = allDao.insert(ApplicationItem(name = "A4"))
var b1 = allDao.insert(Brand(path = "patha", code = "codea", value = "vala"))
var b2 = allDao.insert(Brand(path = "pathb",code = "codeb",value = "valb"))
var b3 = allDao.insert(Brand(path = "pathc",code = "codec",value = "valc"))
allDao.insert(Model(path = "ma",code = "ma",value = "ma",brandCreatorId = b1))
allDao.insert(Model(path = "mb", code = "mb", value = "mb", brandCreatorId = b1))
allDao.insert(Model(path = "mc",code = "mc", value = "mc",brandCreatorId = b2))
allDao.insert(Model(path = "md",code = "md", value = "md", brandCreatorId = b2))
allDao.insert(Model(path = "me", code = "me", value = "me", brandCreatorId = b2))
allDao.insert(ApplicationBrandCrossRef(ai1,b2))
allDao.insert(ApplicationBrandCrossRef(ai1,b3))
allDao.insert(ApplicationBrandCrossRef(ai2,b1))
allDao.insert(ApplicationBrandCrossRef(ai3,b1))
allDao.insert(ApplicationBrandCrossRef(ai3,b2))
allDao.insert(ApplicationBrandCrossRef(ai3,b3))
for(a: ApplicationWithBrandAndModel in allDao.getApplicationItemWithBrandAndTheModels()) {
Log.d(TAG,"AppItem is ${a.application.name}")
for(b: BrandWithModel in a.brands) {
Log.d(TAG,"\tBrand is ${b.brand.code}")
for(m: Model in b.models) {
Log.d(TAG,"\t\tModel is ${m.code}")
}
}
}
结果输出到日志:-
D/APPINFO: AppItem is A1
D/APPINFO: Brand is codeb
D/APPINFO: Model is mc
D/APPINFO: Model is md
D/APPINFO: Model is me
D/APPINFO: Brand is codec
D/APPINFO: AppItem is A2
D/APPINFO: Brand is codea
D/APPINFO: Model is ma
D/APPINFO: Model is mb
D/APPINFO: AppItem is A3
D/APPINFO: Brand is codea
D/APPINFO: Model is ma
D/APPINFO: Model is mb
D/APPINFO: Brand is codeb
D/APPINFO: Model is mc
D/APPINFO: Model is md
D/APPINFO: Model is me
D/APPINFO: Brand is codec
D/APPINFO: AppItem is A4
- 即预期结果