ROOM数据库实体建模

ROOM database entity modeling

一定有更好的方法来做到这一点。我想创建一个包含我所有服装的数据库 table,并包含服装的子类别,如外衣、连衣裙、鞋子等。它们都将具有相同的属性(ID、名称、图像、关于、价格)。我不能创建一个 table 吗?我相信这是一个一对多的关系。

@Serializable
@Entity(tableName = CLOTHING_DATABASE_TABLE)
data class Clothing(
    @PrimaryKey(autoGenerate = false)
    val id: Int,
    val name: String,
    val image: String,
    val about: String,
    val price: String
)

@Serializable
@Entity(tableName = POPULAR_DATABASE_TABLE)
data class Popular(
    @PrimaryKey(autoGenerate = false)
    val popularId: Int,
    val name: String,
    val image: String,
    val about: String,
    val price: String
)

@Serializable
@Entity(tableName = OUTERWEAR_DATABASE_TABLE)
data class Outerwear(
    @PrimaryKey(autoGenerate = false)
    val outerwearId: Int,
    val name: String,
    val image: String,
    val about: String,
    val price: String
)

@Serializable
@Entity(tableName = TOPS_DATABASE_TABLE)
data class Tops(
    @PrimaryKey(autoGenerate = false)
    val topsId: Int,
    val name: String,
    val image: String,
    val about: String,
    val price: String
)

@Serializable
@Entity(tableName = SWIMWEAR_DATABASE_TABLE)
data class Swimwear(
    @PrimaryKey(autoGenerate = false)
    val swimwearId: Int,
    val name: String,
    val image: String,
    val about: String,
    val price: String
)

@Serializable
@Entity(tableName = SHOES_DATABASE_TABLE)
data class Shoes(
    @PrimaryKey(autoGenerate = false)
    val shoesId: Int,
    val name: String,
    val image: String,
    val about: String,
    val price: String
)

@Serializable
@Entity(tableName = BUNDLES_DATABASE_TABLE)
data class Bundles(
    @PrimaryKey(autoGenerate = false)
    val bundlesId: Int,
    val name: String,
    val image: String,
    val about: String,
    val price: String
)

@Serializable
@Entity(tableName = DRESSES_DATABASE_TABLE)
data class Dresses(
    @PrimaryKey(autoGenerate = false)
    val dressesId: Int,
    val name: String,
    val image: String,
    val about: String,
    val price: String
)

@Serializable
@Entity(tableName = PAJAMAS_DATABASE_TABLE)
data class Pajamas(
    @PrimaryKey(autoGenerate = false)
    val pajamasId: Int,
    val name: String,
    val image: String,
    val about: String,
    val price: String
)

@Serializable
@Entity(tableName = ACCESSORIES_DATABASE_TABLE)
data class Accessories(
    @PrimaryKey(autoGenerate = false)
    val accessoriesId: Int,
    val name: String,
    val image: String,
    val about: String,
    val price: String
)

您通常会有 2 或 3 个 table(3 个 many-many,即一件衣服可能有多个 sub-categories)。

对于 one-many 有一个 服装 table 其中有一列 sub-category 引用(相关)单个 sub-category 和一个 sub-category table 是根据唯一列(主键)引用的

对于many-many你有服装table(没有专栏参考单sub-category),sub-categorytable然后一个第三个 table 有两列,一列用于引用服装,另一列用于引用 sub-category,主键是两者的组合。

所以你可以:-

@Entity(tableName = CLOTHING_DATABASE_TABLE)
data class Clothing(
    @PrimaryKey(autoGenerate = false)
    val id: Long, /* should really be Long as */
    val subCategoryReference: Long, /*<<<<< ADDED for the 1 subcategory */
    val name: String,
    val image: String,
    val about: String,
    val price: String
)

和:-

@Entity(tableName = SUBCATEGORY_DATABASE_TABLE)
data class SubCategory(
    @PrimaryKey
    val id: Long?,
    val subCategoryName: String
)
  • 要强制执行参照完整性,您可以将外键约束添加到服装的 subCategoryReference 列 table。

如果您想要一件 many-many,允许一件衣服有多个 sub-categories,那么您可以将第三个 table 作为 :-

@Entity(
    tableName = CLOTHING_SUBCATEGORY_MAP_DATABASE_TABLE,
    primaryKeys = ["clothingMap","subcategoryMap"],
)
data class ClothingSubCategoryMap(
    val clothingMap: Long,
    @ColumnInfo(index = true)
    val subcategoryMap: Long
)

当然你可以有一件衣服 table 并且只有 sub-category 的一列。但是,这将被视为未规范化,因为您将在整个过程中复制 sub-category。

示例 1-many (即使用 2 tables 服装和子类别)

因为您很可能想要连同衣服一起检索 sub-category 那么您将拥有一个使用 @Embedded 和 @Relation 注释的 POJO,例如

data class ClothingWithSingleSubCategory (
    @Embedded
    val clothing: Clothing,
    @Relation(
        entity = SubCategory::class,
        parentColumn = "subCategoryReference",
        entityColumn = "id"
    )
    val subCategory: SubCategory
)

然后您可以将以下内容作为带注释的@Dao class :-

@Dao
interface AllDao {
    @Insert(onConflict = IGNORE)
    fun insert(clothing: Clothing): Long
    @Insert(onConflict = IGNORE)
    fun insert(subCategory: SubCategory): Long
    @Transaction
    @Query("SELECT * FROM clothing")
    fun getAllClothingWithSubCategory(): List<ClothingWithSingleSubCategory>
}

使用 suitable @Database 注释 class 然后你可以在 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()

        val sc_popular = dao.insert(SubCategory(null,"Popular"))
        val sc_outerwear = dao.insert(SubCategory(null,"OuterWear"))
        val sc_tops = dao.insert(SubCategory(null,"Tops"))
        val sc_swimwear = dao.insert(SubCategory(100,"Swimwear"))
        val sc_shoes = dao.insert(SubCategory(null,"Shoes"))
        val sc_dresses = dao.insert(SubCategory(null,"Dresses"))
        val sc_pyjamas = dao.insert(SubCategory(null,"Pyjamas"))

        dao.insert(Clothing(100200300400,sc_popular,"Jeans","jeans_image","blah","100.55"))
        dao.insert(Clothing(100200300500,sc_outerwear,"Anorak","anorak_image","blah","214.55"))

        for (cwsc: ClothingWithSingleSubCategory in dao.getAllClothingWithSubCategory()) {
            Log.d("DBINFO","Name = ${cwsc.clothing.name} Price is ${cwsc.clothing.price} Sub-Category is ${cwsc.subCategory.subCategoryName}")
        }

    }
}

当 运行 日志将包括:-

D/DBINFO: Name = Jeans Price is 100.55 Sub-Category is Popular
D/DBINFO: Name = Anorak Price is 214.55 Sub-Category is OuterWear

示例many-many

与 1-many 一样,您需要一个 POJO,但它具有通过映射 table 获得的 sub-categories 列表。这使用 @Embeded 注释和 @Relation 注释,但扩展为包括 associateBy 以通知 Room 关于中间 table。所以你可以:-

data class ClothingWithListOfSubCategories(
    @Embedded
    val clothing: Clothing,
    @Relation(
        entity = SubCategory::class,
        parentColumn = "id",
        entityColumn = "id",
        associateBy = Junction(
            value = ClothingSubCategoryMap::class,
            parentColumn = "clothingMap",
            entityColumn = "subcategoryMap"
        )
    )
    val subCategories: List<SubCategory>
)

您可以在带注释的@Dao 中包含以下内容 class:-

/* ADDED for many-many */
@Insert(onConflict = IGNORE)
fun insert(clothingSubCategoryMap: ClothingSubCategoryMap): Long
@Transaction
@Query("SELECT * FROM clothing")
fun getAllClothingWithSubCategories(): List<ClothingWithListOfSubCategories>

如果 activity 扩展为包括 :-

    /* Added for many-many */
    /* Note utilises clothing and sub-categories above */
    dao.insert(ClothingSubCategoryMap(jeans,sc_popular))
    dao.insert(ClothingSubCategoryMap(jeans,sc_swimwear))
    dao.insert(ClothingSubCategoryMap(jeans,sc_shoes))
    dao.insert(ClothingSubCategoryMap(anorak,sc_popular))
    dao.insert(ClothingSubCategoryMap(anorak,sc_outerwear))

    for(cwlsc: ClothingWithListOfSubCategories in dao.getAllClothingWithSubCategories()) {
        Log.d("DBINFO","Name = ${cwlsc.clothing.name} Price is ${cwlsc.clothing.price} it is in ${cwlsc.subCategories.size} sub-categories. They are:-")
        for(sc: SubCategory in cwlsc.subCategories) {
            Log.d("DBINFO","\t${sc.subCategoryName}")
        }
    }

日志还将包括:-

D/DBINFO: Name = Jeans Price is 100.55 it is in 3 sub-categories. They are:-
D/DBINFO:   Popular
D/DBINFO:   Swimwear
D/DBINFO:   Shoes
D/DBINFO: Name = Anorak Price is 214.55 it is in 2 sub-categories. They are:-
D/DBINFO:   Popular
D/DBINFO:   OuterWear