如何构建和查询 Room DB 以 return 多个 类 的对象列表?
How to build and query a Room DB to return a list of objects of multiple classes?
请耐心等待,这是一个棘手的问题,我找到的资源并不能真正帮助我解决问题。
我正在尝试在 Kotlin 上构建面向房地产的应用程序。它必须在某个时候显示 RecyclerView
和多个对象 类(例如:房屋、公寓、地块、建筑物等)
我见过多个设计用于接受多个 类 的 RV 示例,但我正在努力将数据库和中介 类 在 table 和 table 之间进行转换POJO。
到目前为止,我已经想到了以下几点:
- 我必须有一个属性 table 来存储每个对象的唯一 ID,以及它的类型的另一个标识符和每个 属性 共有的一系列值(例如,地址、价格等)
- 我必须为每个可以独立列为房地产项目的实体类型(例如,房屋、公寓、一块土地、一栋建筑物,等等)提供一个 table。这些 table 上的每一行都将有一个主外键引用其在属性 table.
上的等效项
现在是意想不到的哈瓦那人。我决定开始根据 RecyclerView
Kotlin codelabs Google 为像我这样的新手组合的项目草拟我的项目。其中以这种方式从数据库中检索数据:
this.plots = Transformations.map(database.RealtorDao.getPlots()) { it.asDomainModel() }
当 DB 向您吐出的列表中的对象都是单一种类时,这就足够顺利了,但是如果您需要它们是不同的,那么会发生什么 类 以便适配器可以告诉它们分开?
或者唯一的解决方法是构建一个巨大的 table,其中包含大约一百个列,其中到处都是空值,并且仅在对象以前面描述的方式解析后才对它们进行排序?
我用头撞墙,直到我厌倦了听到压扁的声音。我无法让 Room DB return 包含多个 class 对象的列表,所以我不得不采用更脏的方法。
如果我只使用数据库 classes 那么我可能已经破解了它,但试图将此类 classes 的对象转换为 POJO 以使用稍微复杂的东西。
我找到的解决方法是制作一个主房地产 class 并接受它在数据库中会有很多很多空字段。虽然与理想相去甚远,但它确实有效。
数据库对象 classes:
open class DatabaseProperty
{
@ColumnInfo(name = COL_TYPE)
@SerializedName(COL_TYPE)
@Expose
var type: String? = null
@ColumnInfo(name = COL_ADDRESS)
@SerializedName(COL_ADDRESS)
@Expose
var address: String? = null
@ColumnInfo(name = COL_OWNER)
@SerializedName(COL_OWNER)
@Expose
var owner: String? = null
@ColumnInfo(name = COL_PRICE_FINAL)
@SerializedName(COL_PRICE_FINAL)
@Expose
var priceFinal: Long? = null
@ColumnInfo(name = COL_PRICE_QUOTED)
@SerializedName(COL_PRICE_QUOTED)
@Expose
var priceQuoted: Long? = null
/**
* No args constructor for use in serialization
*/
constructor()
@Ignore
constructor
(
type: String,
address: String,
owner: String,
priceFinal: Long,
priceQuoted: Long
) : super() {
this.type = type
this.address = address
this.owner = owner
this.priceFinal = priceFinal
this.priceQuoted = priceQuoted
}
}
@Entity
(
tableName = TABLE_RE,
indices =
[
Index(value = [COL_RE_ID], unique = true)
],
foreignKeys =
[
ForeignKey
(
entity = DatabaseRealEstate::class,
parentColumns = arrayOf(COL_RE_ID),
childColumns = arrayOf(COL_PARENT_ID),
onDelete = ForeignKey.NO_ACTION
)
]
)
data class DatabaseRealEstate
(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = COL_RE_ID)
var id: Int? = null,
@ColumnInfo(name = COL_PARENT_ID)
var parent_id: Int? = null,
@Embedded(prefix = RE)
var property: DatabaseProperty? = null,
@ColumnInfo(name = COL_PARCEL_FRONT) // Plot front
@SerializedName(COL_PARCEL_FRONT)
@Expose
var front: Float? = null,
@ColumnInfo(name = COL_PARCEL_SIDE) // Plot side
@SerializedName(COL_PARCEL_SIDE)
@Expose
var side: Float? = null,
@ColumnInfo(name = COL_AREA) // Plot area
@SerializedName(COL_AREA)
@Expose
var area: Float? = null,
@ColumnInfo(name = COL_CATASTER)
@SerializedName(COL_CATASTER)
@Expose
var cataster: String? = null,
@ColumnInfo(name = COL_ZONIFICATION)
@SerializedName(COL_ZONIFICATION)
@Expose
var zonification: String? = null,
)
data class RealEstateWithSubunits
(
@Embedded
val re: DatabaseRealEstate? = null,
@Relation
(
parentColumn = COL_RE_ID,
entityColumn = COL_PARENT_ID,
entity = DatabaseRealEstate::class
)
var subunits: List<DatabaseRealEstate>? = null,
@Relation
(
parentColumn = COL_RE_ID,
entityColumn = COL_PARENT_ID,
entity = DatabaseChamber::class
)
var chambers: List<DatabaseChamber>? = null
)
fun List<RealEstateWithSubunits>.asRESUBDomainModel() : List<RealEstate>
{
return map { obj ->
RealEstate(
id = obj.re!!.id!!,
type = obj.re.property!!.type!!,
address = obj.re.property!!.address!!,
owner = obj.re.property!!.owner!!,
priceFinal = obj.re.property!!.priceFinal!!,
priceQuoted = obj.re.property!!.priceQuoted!!,
parent_id = obj.re.parent_id,
front = obj.re.front,
side = obj.re.side,
area = obj.re.area,
cataster = obj.re.cataster,
zonification = obj.re.zonification,
chambers = obj.chambers!!.asChamberDomainModel(),
subunits = obj.subunits!!.asREDomainModel()
)
}
}
fun List<DatabaseChamber>.asChamberDomainModel(): List<Chamber>
{
return map {
Chamber(
id = it.id,
parent_id = it.parent_id,
front = it.front,
side = it.side,
area = it.area
)
}
}
fun List<DatabaseRealEstate>.asREDomainModel(): List<RealEstate>
{
return map { obj ->
RealEstate(
id = obj.id!!,
type = obj.property!!.type!!,
address = obj.property!!.address!!,
owner = obj.property!!.owner!!,
priceFinal = obj.property!!.priceFinal!!,
priceQuoted = obj.property!!.priceQuoted!!,
parent_id = obj.parent_id,
front = obj.front,
side = obj.side,
area = obj.area,
cataster = obj.cataster,
zonification = obj.zonification,
chambers = ArrayList(),
subunits = ArrayList()
)
}
}
模型对象 classes:
interface BaseProperty {
var id: Int
var type: String
var address: String
var owner: String
var priceFinal: Long
var priceQuoted: Long
}
data class RealEstate(
override var id: Int = -1,
override var type: String = "",
override var address: String = "",
override var owner: String = "",
override var priceFinal: Long = 0,
override var priceQuoted: Long = 0,
var parent_id: Int?,
var front: Float?,
var side: Float?,
var area: Float?,
var cataster: String?,
var zonification: String?,
var subunits: List<RealEstate>? = null,
var chambers: List<Chamber>? = null
) : BaseProperty
{
fun hasParent() : Boolean
{
if (parent_id == null)
{
return false
}
return true
}
}
我还没有找到更好的方法,所以如果有人找到了,我张开双臂欢迎它。
请耐心等待,这是一个棘手的问题,我找到的资源并不能真正帮助我解决问题。
我正在尝试在 Kotlin 上构建面向房地产的应用程序。它必须在某个时候显示 RecyclerView
和多个对象 类(例如:房屋、公寓、地块、建筑物等)
我见过多个设计用于接受多个 类 的 RV 示例,但我正在努力将数据库和中介 类 在 table 和 table 之间进行转换POJO。
到目前为止,我已经想到了以下几点:
- 我必须有一个属性 table 来存储每个对象的唯一 ID,以及它的类型的另一个标识符和每个 属性 共有的一系列值(例如,地址、价格等)
- 我必须为每个可以独立列为房地产项目的实体类型(例如,房屋、公寓、一块土地、一栋建筑物,等等)提供一个 table。这些 table 上的每一行都将有一个主外键引用其在属性 table. 上的等效项
现在是意想不到的哈瓦那人。我决定开始根据 RecyclerView
Kotlin codelabs Google 为像我这样的新手组合的项目草拟我的项目。其中以这种方式从数据库中检索数据:
this.plots = Transformations.map(database.RealtorDao.getPlots()) { it.asDomainModel() }
当 DB 向您吐出的列表中的对象都是单一种类时,这就足够顺利了,但是如果您需要它们是不同的,那么会发生什么 类 以便适配器可以告诉它们分开?
或者唯一的解决方法是构建一个巨大的 table,其中包含大约一百个列,其中到处都是空值,并且仅在对象以前面描述的方式解析后才对它们进行排序?
我用头撞墙,直到我厌倦了听到压扁的声音。我无法让 Room DB return 包含多个 class 对象的列表,所以我不得不采用更脏的方法。
如果我只使用数据库 classes 那么我可能已经破解了它,但试图将此类 classes 的对象转换为 POJO 以使用稍微复杂的东西。
我找到的解决方法是制作一个主房地产 class 并接受它在数据库中会有很多很多空字段。虽然与理想相去甚远,但它确实有效。
数据库对象 classes:
open class DatabaseProperty
{
@ColumnInfo(name = COL_TYPE)
@SerializedName(COL_TYPE)
@Expose
var type: String? = null
@ColumnInfo(name = COL_ADDRESS)
@SerializedName(COL_ADDRESS)
@Expose
var address: String? = null
@ColumnInfo(name = COL_OWNER)
@SerializedName(COL_OWNER)
@Expose
var owner: String? = null
@ColumnInfo(name = COL_PRICE_FINAL)
@SerializedName(COL_PRICE_FINAL)
@Expose
var priceFinal: Long? = null
@ColumnInfo(name = COL_PRICE_QUOTED)
@SerializedName(COL_PRICE_QUOTED)
@Expose
var priceQuoted: Long? = null
/**
* No args constructor for use in serialization
*/
constructor()
@Ignore
constructor
(
type: String,
address: String,
owner: String,
priceFinal: Long,
priceQuoted: Long
) : super() {
this.type = type
this.address = address
this.owner = owner
this.priceFinal = priceFinal
this.priceQuoted = priceQuoted
}
}
@Entity
(
tableName = TABLE_RE,
indices =
[
Index(value = [COL_RE_ID], unique = true)
],
foreignKeys =
[
ForeignKey
(
entity = DatabaseRealEstate::class,
parentColumns = arrayOf(COL_RE_ID),
childColumns = arrayOf(COL_PARENT_ID),
onDelete = ForeignKey.NO_ACTION
)
]
)
data class DatabaseRealEstate
(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = COL_RE_ID)
var id: Int? = null,
@ColumnInfo(name = COL_PARENT_ID)
var parent_id: Int? = null,
@Embedded(prefix = RE)
var property: DatabaseProperty? = null,
@ColumnInfo(name = COL_PARCEL_FRONT) // Plot front
@SerializedName(COL_PARCEL_FRONT)
@Expose
var front: Float? = null,
@ColumnInfo(name = COL_PARCEL_SIDE) // Plot side
@SerializedName(COL_PARCEL_SIDE)
@Expose
var side: Float? = null,
@ColumnInfo(name = COL_AREA) // Plot area
@SerializedName(COL_AREA)
@Expose
var area: Float? = null,
@ColumnInfo(name = COL_CATASTER)
@SerializedName(COL_CATASTER)
@Expose
var cataster: String? = null,
@ColumnInfo(name = COL_ZONIFICATION)
@SerializedName(COL_ZONIFICATION)
@Expose
var zonification: String? = null,
)
data class RealEstateWithSubunits
(
@Embedded
val re: DatabaseRealEstate? = null,
@Relation
(
parentColumn = COL_RE_ID,
entityColumn = COL_PARENT_ID,
entity = DatabaseRealEstate::class
)
var subunits: List<DatabaseRealEstate>? = null,
@Relation
(
parentColumn = COL_RE_ID,
entityColumn = COL_PARENT_ID,
entity = DatabaseChamber::class
)
var chambers: List<DatabaseChamber>? = null
)
fun List<RealEstateWithSubunits>.asRESUBDomainModel() : List<RealEstate>
{
return map { obj ->
RealEstate(
id = obj.re!!.id!!,
type = obj.re.property!!.type!!,
address = obj.re.property!!.address!!,
owner = obj.re.property!!.owner!!,
priceFinal = obj.re.property!!.priceFinal!!,
priceQuoted = obj.re.property!!.priceQuoted!!,
parent_id = obj.re.parent_id,
front = obj.re.front,
side = obj.re.side,
area = obj.re.area,
cataster = obj.re.cataster,
zonification = obj.re.zonification,
chambers = obj.chambers!!.asChamberDomainModel(),
subunits = obj.subunits!!.asREDomainModel()
)
}
}
fun List<DatabaseChamber>.asChamberDomainModel(): List<Chamber>
{
return map {
Chamber(
id = it.id,
parent_id = it.parent_id,
front = it.front,
side = it.side,
area = it.area
)
}
}
fun List<DatabaseRealEstate>.asREDomainModel(): List<RealEstate>
{
return map { obj ->
RealEstate(
id = obj.id!!,
type = obj.property!!.type!!,
address = obj.property!!.address!!,
owner = obj.property!!.owner!!,
priceFinal = obj.property!!.priceFinal!!,
priceQuoted = obj.property!!.priceQuoted!!,
parent_id = obj.parent_id,
front = obj.front,
side = obj.side,
area = obj.area,
cataster = obj.cataster,
zonification = obj.zonification,
chambers = ArrayList(),
subunits = ArrayList()
)
}
}
模型对象 classes:
interface BaseProperty {
var id: Int
var type: String
var address: String
var owner: String
var priceFinal: Long
var priceQuoted: Long
}
data class RealEstate(
override var id: Int = -1,
override var type: String = "",
override var address: String = "",
override var owner: String = "",
override var priceFinal: Long = 0,
override var priceQuoted: Long = 0,
var parent_id: Int?,
var front: Float?,
var side: Float?,
var area: Float?,
var cataster: String?,
var zonification: String?,
var subunits: List<RealEstate>? = null,
var chambers: List<Chamber>? = null
) : BaseProperty
{
fun hasParent() : Boolean
{
if (parent_id == null)
{
return false
}
return true
}
}
我还没有找到更好的方法,所以如果有人找到了,我张开双臂欢迎它。