【问题标题】:How to build and query a Room DB to return a list of objects of multiple classes?如何构建和查询 Room DB 以返回多个类的对象列表?
【发布时间】:2021-01-16 16:59:07
【问题描述】:

请耐心等待,这是一个棘手的问题,我发现的哪些资源并不能真正帮助我解决问题。

我正在尝试在 Kotlin 上构建一个面向房地产的应用程序。它必须在某个时候显示具有多个对象类的RecyclerView(例如:房屋、公寓、地块、建筑物等)

我见过多个设计为接受多个类的 RV 示例,但我正在努力将数据库和在表和 POJO 之间转换的中间类放在一起。

到目前为止,我已经想到了以下几点:

  • 我必须有一个 Properties 表来存储每个对象的唯一 ID、其类型的另一个标识符以及每个属性共有的一系列值(例如,地址、价格等)
  • 我必须为每个实体类型提供一个表格,可以独立列为房地产项目(例如,房子、公寓、一块土地、建筑物,你有什么)。这些表上的每一行都有一个主外键,引用其在 Properties 表上的等效项。

现在是意想不到的哈瓦那人。我决定根据 Google 为像我这样的新手准备的 RecyclerView Kotlin codelabs 开始草拟我的项目。其中数据以这种方式从数据库中检索:

this.plots = Transformations.map(database.RealtorDao.getPlots()) { it.asDomainModel() }

当数据库向您吐出的列表中的对象都是单一类型时,这很顺利,但是如果您需要它们属于不同的类以便适配器可以区分它们会发生什么?

或者唯一的解决方法是构建一个包含大约一百列的巨大表,其中到处都有空值,并且只有在以前面描述的方式解析对象之后才对对象进行排序?

【问题讨论】:

    标签: android sqlite kotlin android-recyclerview room


    【解决方案1】:

    我把头撞在这堵墙上,直到我厌倦了听到挤压的声音。我无法让 Room DB 返回多个类的对象列表,因此我不得不采用更脏的方法。

    如果我只使用数据库类,那么我可能会破解它,但尝试将此类类的对象转换为 POJO 以使用有些复杂的东西。

    我发现的解决方法是创建一个房地产大师课程,并接受它在数据库中会有大量的空字段。虽然与理想相去甚远,但它确实有效。

    数据库对象类:

    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()
            )
        }
    }
    

    模型对象类:

    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
        }
    }
    

    我还没有找到更好的方法,所以如果有人找到了,我会张开双臂欢迎它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-14
      • 1970-01-01
      • 2018-05-25
      • 1970-01-01
      • 1970-01-01
      • 2020-12-12
      • 2021-05-17
      相关资源
      最近更新 更多