【问题标题】:How to build RoomDB in Kotlin with @Embedded table which contains some entity tables and the same @Embedded table, which contains entity too?如何在 Kotlin 中使用包含一些实体表的 @Embedded 表和同样包含实体的 @Embedded 表在 Kotlin 中构建 RoomDB?
【发布时间】:2022-01-02 19:30:00
【问题描述】:

错误:类必须是@Entity 或@DatabaseView。 公共最终类 StructuralObjectItemDB { ^

我有以下数据结构(来自 Json):

我想获取带有表的数据库:BuildingItemEntityDB、StructuralObjectItemEntityDB、AddressOjectItemEntityDB 和 IconItemEntityDB。 为了为“建筑项目”(包括 AddressItemEntityDB 和 StructuralObjectItemDB 列表)编写方法 getItems(),我使用 @Embedded 注释和两个 @Relations 制作了 BuildingItemDB。 我还创建了类 StructuralObjectItemDB(包括 IconItemEntityDB),以便为“StructuralObject Items”编写方法 getItems()。 问题是 RoomDB 不能让我将 StructuralObjectItemDB 存储在 BuildingItemDB 中,因为这不是 @Entity 或 @DatabaseView,但我需要它。在这种情况下我该怎么办?

BuildingItemDB.kt

package com.example.data.roomDB.entities.buildingItem

import androidx.room.Embedded
import androidx.room.Relation
import com.example.data.roomDB.entities.buildingItem.adressItem.AddressItemEntityDB
import com.example.data.roomDB.entities.buildingItem.structuralObjectItem.StructuralObjectItemDB

data class BuildingItemDB (

    @Embedded
    val buildingItemEntityDB: BuildingItemEntityDB,

    @Relation(
        parentColumn = "id",
        entityColumn = "buildingItemId"
    )
    val structuralObjectEntities: List<StructuralObjectItemDB>,

    @Relation(
        parentColumn = "id",
        entityColumn = "buildingItemId"
    )
    val address: AddressItemEntityDB,

    )

BuildingItemEntity.kt

package com.example.data.roomDB.entities.buildingItem

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "buildings")
data class BuildingItemEntityDB(

    @PrimaryKey
    val id: String,

    @ColumnInfo(name = "inventoryUsrreNumber")
    val inventoryUsrreNumber: String?,

    @ColumnInfo(name = "name")
    val name: String?,

    @ColumnInfo(name = "isModern")
    val isModern: Boolean?,

    @ColumnInfo(name = "type")
    val type: String?,

    @ColumnInfo(name = "markerPath")
    val markerPath: String?

)

BuildingItemDAO.kt

package com.example.data.roomDB.entities.buildingItem

import androidx.room.*
import com.example.data.roomDB.entities.buildingItem.adressItem.AddressItemDAO
import com.example.data.roomDB.entities.buildingItem.adressItem.AddressItemEntityDB
import com.example.data.roomDB.entities.buildingItem.structuralObjectItem.StructuralObjectItemDAO
import kotlinx.coroutines.flow.Flow

@Dao
interface BuildingItemDAO : StructuralObjectItemDAO, AddressItemDAO {

    // This operations are needed for entities. We'll use it in more difficult queries
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertBuildingItemEntityDB(buildingItemEntityDB: BuildingItemEntityDB): Long
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertAddressItemEntityDB(address: AddressItemEntityDB?): Long
    @Update
    fun updateBuildingItemEntityDB(buildingItemEntityDB: BuildingItemEntityDB)
    @Update
    fun updateAddressItemEntityDB(address: AddressItemEntityDB?)
    @Delete
    fun deleteBuildingItemEntityDB(buildingItemEntityDB: BuildingItemEntityDB)
    @Delete
    fun deleteAddressItemEntityDB(address: AddressItemEntityDB?)

    @Transaction
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertOneBuildingItem(item: BuildingItemDB): Long {
        val resultValue = insertBuildingItemEntityDB(item.buildingItemEntityDB)
        insertStructuralObjectItemsList(item.structuralObjectEntities)
        insertAddressItemEntityDB(item.address)
        return resultValue
    }

    @Transaction
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertBuildingItemsList(items: List<BuildingItemDB>) {
        for (bi: BuildingItemDB in items) {
            insertOneBuildingItem(bi)
        }
    }

    @Transaction
    @Update
    suspend fun updateOneBuildingItem(item: BuildingItemDB) {
        updateBuildingItemEntityDB(item.buildingItemEntityDB)
        updateAllStructuralObjectItems(item.structuralObjectEntities)
        updateAddressItemEntityDB(item.address)
    }

    @Transaction
    @Update
    suspend fun updateAllBuildingItems(items: List<BuildingItemDB>) {
        for (bi: BuildingItemDB in items) {
            updateOneBuildingItem(bi)
        }
    }

    @Transaction
    @Delete
    suspend fun deleteOneBuildingItem(item: BuildingItemDB, deleteChildLocations: Boolean) {
        if (deleteChildLocations) {
            deleteAllStructuralObjectItems(item.structuralObjectEntities, deleteChildLocations)
            deleteAddressItemEntityDB(item.address)
        }
        deleteBuildingItemEntityDB(item.buildingItemEntityDB)
    }

    @Transaction
    @Delete
    suspend fun deleteAllBuildingItems(items: List<BuildingItemDB>, deleteChildLocations: Boolean) {
        for (bi: BuildingItemDB in items) {
            deleteOneBuildingItem(bi, deleteChildLocations)
        }
    }

    @Transaction
    @Query("SELECT * FROM buildings ORDER BY id")
    fun getAllBuildingItems(): Flow<List<BuildingItemDB>>

    @Transaction
    @Query("SELECT * FROM buildings WHERE id = :neededId")
    fun getBuildingItemById(neededId: String): Flow<BuildingItemDB>

}

StructuralObjectItemDB.kt

package com.example.data.roomDB.entities.buildingItem.structuralObjectItem

import androidx.room.*
import com.example.data.roomDB.entities.buildingItem.structuralObjectItem.iconItem.IconItemEntityDB

data class StructuralObjectItemDB(

    @Embedded
    val structuralItemsEntityDB: StructuralObjectItemEntityDB,

    @ColumnInfo(name = "buildingItemId")
    val buildingItemId: String?,

    @Relation(
        parentColumn = "id",
        entityColumn = "structuralObjectItemId"
    )
    val icon: IconItemEntityDB,

    )

StructuralObjectItemEntityDB.kt

package com.example.data.roomDB.entities.buildingItem.structuralObjectItem

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "structuralObjects")
data class StructuralObjectItemEntityDB(

    @PrimaryKey
    val id: String,

    @ColumnInfo(name = "subdivision")
    val subdivision: String?,

    @ColumnInfo(name = "description")
    val description: String?,

    @ColumnInfo(name = "website")
    val website: String?,

    @ColumnInfo(name = "buildingId")
    val buildingId: String?,

    @ColumnInfo(name = "category")
    val category: String?,

)

StructuralObjectItemDAO.kt

package com.example.data.roomDB.entities.buildingItem.structuralObjectItem

import androidx.room.*
import com.example.data.roomDB.entities.buildingItem.structuralObjectItem.iconItem.IconItemDAO
import com.example.data.roomDB.entities.buildingItem.structuralObjectItem.iconItem.IconItemEntityDB
import kotlinx.coroutines.flow.Flow

@Dao
interface StructuralObjectItemDAO : IconItemDAO {

    // This operations are needed for entities. We'll use it in more difficult queries
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertStructuralObjectItemEntityDB(structuralItemsEntityDB: StructuralObjectItemEntityDB): Long
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertIconItemEntityDB(icon: IconItemEntityDB?): Long
    @Update
    fun updateStructuralObjectItemEntityDB(structuralItemsEntityDB: StructuralObjectItemEntityDB)
    @Update
    fun updateIconItemEntityDB(icon: IconItemEntityDB?)
    @Delete
    fun deleteStructuralObjectItemEntityDB(structuralItemsEntityDB: StructuralObjectItemEntityDB)
    @Delete
    fun deleteIconItemEntityDB(icon: IconItemEntityDB?)

    @Transaction
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertOneStructuralObjectItem(item: StructuralObjectItemDB): Long {
        val resultValue = insertStructuralObjectItemEntityDB(item.structuralItemsEntityDB)
        insertIconItemEntityDB(item.icon)
        return resultValue
    }

    @Transaction
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertStructuralObjectItemsList(items: List<StructuralObjectItemDB>) {
        for (soi: StructuralObjectItemDB in items) {
            insertOneStructuralObjectItem(soi)
        }
    }

    @Transaction
    @Update
    suspend fun updateOneStructuralObjectItem(item: StructuralObjectItemDB) {
        updateStructuralObjectItemEntityDB(item.structuralItemsEntityDB)
        updateIconItemEntityDB(item.icon)
    }

    @Transaction
    @Update
    suspend fun updateAllStructuralObjectItems(items: List<StructuralObjectItemDB>) {
        for (soi: StructuralObjectItemDB in items) {
            updateOneStructuralObjectItem(soi)
        }
    }

    @Transaction
    @Delete
    suspend fun deleteOneStructuralObjectItem(item: StructuralObjectItemDB, deleteChildLocations: Boolean) {
        if (deleteChildLocations) {
            deleteIconItemEntityDB(item.icon)
        }
        deleteStructuralObjectItemEntityDB(item.structuralItemsEntityDB)
    }

    @Transaction
    @Delete
    suspend fun deleteAllStructuralObjectItems(items: List<StructuralObjectItemDB>, deleteChildLocations: Boolean) {
        for (soi: StructuralObjectItemDB in items) {
            deleteOneStructuralObjectItem(soi, deleteChildLocations)
        }
    }

    @Transaction
    @Query("SELECT * FROM structuralObjects ORDER BY id")
    fun getAllStructuralObjectItems(): Flow<List<StructuralObjectItemDB>>

    @Transaction
    @Query("SELECT * FROM structuralObjects WHERE id = :neededId")
    fun getStructuralObjectItemById(neededId: String): Flow<StructuralObjectItemDB>

}

AddressItemEntity.kt

package com.example.data.roomDB.entities.buildingItem.adressItem

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "addresses")
data class AddressItemEntityDB(

    @PrimaryKey
    val id: String,

    @ColumnInfo(name = "buildingItemId")
    val buildingItemId: String?,

    @ColumnInfo(name = "description")
    val description: String?,

    @ColumnInfo(name = "latitude")
    val latitude: String?,

    @ColumnInfo(name = "longitude")
    val longitude: String?

)

AddressItemDAO.kt

package com.example.data.roomDB.entities.buildingItem.adressItem

import androidx.room.*
import kotlinx.coroutines.flow.Flow

@Dao
interface AddressItemDAO {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertOneAddressItem(item: AddressItemEntityDB)

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertAddressItemsList(items: List<AddressItemEntityDB>)

    @Update
    suspend fun updateOneAddressItem(item: AddressItemEntityDB)

    @Update
    suspend fun updateAllAddressItems(items: List<AddressItemEntityDB>)

    @Delete
    suspend fun deleteOneAddressItem(item: AddressItemEntityDB)

    @Delete
    suspend fun deleteAllAddressItems(items: List<AddressItemEntityDB>)

    @Query("SELECT * FROM addresses ORDER BY id")
    fun getAllAddressItems(): Flow<List<AddressItemEntityDB>>

    @Query("SELECT * FROM addresses WHERE id = :neededId")
    fun getAddressItemById(neededId: String): Flow<AddressItemEntityDB>

}

IconItemEntityDB.kt

package com.example.data.roomDB.entities.buildingItem.structuralObjectItem.iconItem

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "icons")
data class IconItemEntityDB(

    @PrimaryKey
    val id: String,

    @ColumnInfo(name = "structuralObjectItemId")
    val structuralObjectItemId: String?,

    @ColumnInfo(name = "subdivision")
    val subdivision: String?,

    @ColumnInfo(name = "logoPath")
    val logoPath: String?

)

IconItemDAO.kt

package com.example.data.roomDB.entities.buildingItem.structuralObjectItem.iconItem

import androidx.room.*
import kotlinx.coroutines.flow.Flow

@Dao
interface IconItemDAO {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertOneIconItem(item: IconItemEntityDB)

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertIconItemsList(items: List<IconItemEntityDB>)

    @Update
    suspend fun updateOneIconItem(item: IconItemEntityDB)

    @Update
    suspend fun updateAllIconItems(items: List<IconItemEntityDB>)

    @Delete
    suspend fun deleteOneIconItem(item: IconItemEntityDB)

    @Delete
    suspend fun deleteAllIconItems(items: List<IconItemEntityDB>)

    @Query("SELECT * FROM icons ORDER BY id")
    fun getAllIconItems(): Flow<List<IconItemEntityDB>>

    @Query("SELECT * FROM icons WHERE id = :neededId")
    fun getIconItemById(neededId: String): Flow<IconItemEntityDB>

}

【问题讨论】:

    标签: android database android-studio kotlin android-room


    【解决方案1】:

    我已经解决了我的问题。 我所做的决定是将 StructuralObjectItemDB 分成两个实体(StructruralObjectItemEntityDB 和 IconItemEntityDB)并尝试分别获取它们......所以,我们只能使用实体,或者我们可以尝试@DatabaseView,但你需要为它编写 INNER JOIN 查询... 现在是 BuildingItemDB.kt:

    package com.example.data.roomDB.entities.buildingItem
    

    导入 androidx.room.Embedded 导入 androidx.room.Relation 导入 com.example.data.roomDB.entities.buildingItem.adressItem.AddressItemEntityDB 导入 com.example.data.roomDB.entities.buildingItem.structuralObjectItem.StructuralObjectItemEntityDB 导入 com.example.data.roomDB.entities.buildingItem.structuralObjectItem.iconItem.IconItemEntityDB

    数据类 BuildingItemDB (

    // This class is needed for getItems() method in BuildingItemDAO
    // This is a combination of:
    // 1) AddressItemEntity table
    // 2) StructuralObjectItemEntity table
    // 3) IconItemEntityDB
    // This class can only be used in SELECT queries, not in INSERT, UPDATE, DELETE
    
    @Embedded
    val buildingItemEntityDB: BuildingItemEntityDB,
    
    @Relation(
        parentColumn = "id",
        entityColumn = "buildingItemId"
    )
    val structuralObjectEntities: List<StructuralObjectItemEntityDB>,
    
    @Relation(
        parentColumn = "id",
        entityColumn = "buildingItemId"
    )
    val iconEntities: List<IconItemEntityDB>,
    
    @Relation(
        parentColumn = "id",
        entityColumn = "buildingItemId"
    )
    val address: AddressItemEntityDB
    

    )

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-26
      • 2016-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-29
      • 1970-01-01
      • 2014-02-19
      相关资源
      最近更新 更多