【问题标题】:Insert relation in Room android在房间 android 中插入关系
【发布时间】:2021-10-08 03:25:56
【问题描述】:

我对如何在房间中插入关系有疑问。所以,我有Product 和ProductsList 实体。 ProductsList 可能有很多 Products,但 products 不应该知道它们包含在哪里的列表。

@Entity(tableName = "products")
data class Product(
    @PrimaryKey(autoGenerate = true)
    val productId: Long,

    val productName: String
)
@Entity
data class ProductList(
    @PrimaryKey(autoGenerate = true)
    val productListId: Long,
    val listName: String
)

我创建了 ProductsListWithProducts 类:

data class ProductListWithProducts(
    @Embedded
    val productList: ProductList,

    @Relation(
        parentColumn = "productListId",
        entityColumn = "productId",
        entity = Product::class
    )
    val productsId: List<Product>
)

但我不明白如何在数据库中插入数据。例如,我已经在其表中添加了Products,并且在它想要创建新的ProductList 之后。我检查了其他答案,发现它只是使用 Dao 插入它:

@Dao
abstract class ProductListDao {

    @Transaction
    fun insert(productList: ProductList, products: List<Product>) {
        insert(productList)
        for (product in products) {
            insert(product)
        }
    }

但我看不到如何在这些表之间添加关系,因为我不想在产品实体中添加外键(因为在这种情况下我需要创建多对多关系)。我想到了其他实体

@Entity(primaryKeys = ["productId", "productListId"])
data class ProductListProducts(
    val productId: Long,
    val productListId: Long
)

但它也用于定义多对多关系。

我可以在不创建多对多关系的情况下添加此关系,而只是一对多吗?

【问题讨论】:

    标签: android android-room


    【解决方案1】:

    是的,有 ProductListProducts,但您不妨考虑使用:-

    @Entity(
        primaryKeys = ["productId", "productListId"]
        ,indices = [
            Index(value = ["productListId"]) /* Index else Room warns */
        ]
        /* Foreign Keys are optional BUT enforce referential integrity */
        , foreignKeys = [
            ForeignKey(
                entity = Product::class,
                parentColumns = ["productId"],
                childColumns = ["productId"],
                onDelete = ForeignKey.CASCADE,
                onUpdate = ForeignKey.CASCADE
            ),
            ForeignKey(
                entity = ProductList::class,
                parentColumns = ["productListId"],
                childColumns = ["productListId"],
                onDelete = ForeignKey.CASCADE,
                onUpdate = ForeignKey.CASCADE
            )
        ]
        )
    data class ProductListProducts(
        val productId: Long,
        val productListId: Long
    )
    

    这是一个关联表(参考表、映射表和许多其他术语)。因此,您使用的关系利用 association 作为 ProductList 和 Product 之间的 Junction。因此,您的 ProductListWithProducts POJO 变为:-

    data class ProductListWithProducts (
        @Embedded
        val productList: ProductList,
        @Relation(
            entity = Product::class,
            parentColumn = "productListId",
            entityColumn = "productId",
            associateBy = Junction(
                ProductListProducts::class,
                parentColumn = "productListId",
                entityColumn = "productId"
            )
        )
        val product: List<Product>
    )
    

    演示使用上述类(以及您的 id 已更改为 Long=0 的类)

    使用 Dao 类,例如:-

    @Dao
    abstract class AllDao {
        @Insert
        abstract fun insert(product: Product): Long
        @Insert
        abstract fun insert(productList: ProductList): Long
        @Insert
        abstract fun insert(productListProducts: ProductListProducts): Long
        @Transaction
        @Query("SELECT * FROM ProductList")
        abstract fun getProductListWithProducts(): List<ProductListWithProducts>
    }
    

    然后是以下(为了简洁/方便在主线程上运行):-

        db = TheDatabase.getInstance(this)
        dao = db.getAllDao()
    
        var p1 = dao.insert(Product( productName = "Product1"))
        var p2 = dao.insert(Product(productName = "Product2"))
        var pl1 = dao.insert(ProductList(listName = "List1"))
        var pl2 = dao.insert(ProductList(listName = "List2"))
        dao.insert(ProductListProducts(p1,pl1))
        dao.insert(ProductListProducts(p1,pl2))
        dao.insert(ProductListProducts(p2,pl1))
    
        dao.insert(ProductListProducts(dao.insert(Product(productName = "Product3")),dao.insert(
            ProductList(listName = "List3")))
        )
        for(plwp: ProductListWithProducts in dao.getProductListWithProducts()) {
            Log.d(TAG,"ProductList is ${plwp.productList.listName} ID is ${plwp.productList.productListId}")
            for(p: Product in plwp.product) {
                Log.d(TAG,"\t Product is ${p.productName} ID is ${p.productId}")
            }
        }
    

    导致日志包含:-

    D/DBINFO: ProductList is List1 ID is 1
    D/DBINFO:    Product is Product1 ID is 1
    D/DBINFO:    Product is Product2 ID is 2
    D/DBINFO: ProductList is List2 ID is 2
    D/DBINFO:    Product is Product1 ID is 1
    D/DBINFO: ProductList is List3 ID is 3
    D/DBINFO:    Product is Product3 ID is 3
    

    我可以在不创建多对多关系的情况下添加此关系,而只是一对多吗?

    上述(即关联表)将处理 1 到多个,但如果您不想要额外的表,那么您必须在子表中包含父级的标识符。您可以通过使 1 的列唯一来在关联表中强制执行 1-many。

    至于你说的 Mass 类型插入

    例如,我已经在它的表中添加了 Products 并且在它想要创建新的 ProductList 之后

    那么你也许可以通过以下额外的@Dao 来进行:-

    @Insert
    abstract fun insert(productListList: List<ProductList>): LongArray
    @Insert
    abstract fun insertManyProductListProducts(productListProductsList: List<ProductListProducts>): LongArray
    
    
    
    /* This can be used to get a specific product or products according to a pattern */
    /* e.g. */
    /*  if productPatterName is product1 then an exact match */
    /* if prod% then all that start with prod */
    /* if %prod all that end in prod */
    /* if %prod% then all that have prod anywhere */
    @Query("SELECT productId FROM products WHERE productName LIKE :productNamePattern")
    abstract fun getProductIdByName(productNamePattern: String): LongArray
    

    然后有如下代码:-

        /* Adding many new ProductLists to existing Products */
        /* 1 add the new ProductLists */
        /*      Noting that the insert returns an array of the productListId's inserted */
        val insertedProductLists = dao.insert(
            listOf(
                ProductList(listName = "ListX1"),
                ProductList(listName = "ListX2")
            )
        )
        /* 2. Determine the Product(s) that will be related to the new list of ProductLists */
        val productIdList = dao.getProductIdByName("Product%") /* All products */
        /* 3. Prepare the List of ProductListProducts for mass insertion */
        val plplist: ArrayList<ProductListProducts> = ArrayList()
        for(pid: Long in productIdList) {
            for(plid: Long in insertedProductLists) {
                plplist.add(ProductListProducts(pid,plid))
            }
        }
        /* 4. add the relationships */
        dao.insertManyProductListProducts(plplist)
    
    • 如果您想要 1 个现有产品,例如product1 那么你可以使用dao.getProductIdByName("Product1"),当然你也可以增加/减少Array中的productLists来适应。

    这将导致:-

    D/DBINFO: ProductList is List1 ID is 1
    D/DBINFO:    Product is Product1 ID is 1
    D/DBINFO:    Product is Product2 ID is 2
    D/DBINFO: ProductList is List2 ID is 2
    D/DBINFO:    Product is Product1 ID is 1
    D/DBINFO: ProductList is List3 ID is 3
    D/DBINFO:    Product is Product3 ID is 3
    D/DBINFO: ProductList is ListX1 ID is 4
    D/DBINFO:    Product is Product1 ID is 1
    D/DBINFO:    Product is Product2 ID is 2
    D/DBINFO:    Product is Product3 ID is 3
    D/DBINFO: ProductList is ListX2 ID is 5
    D/DBINFO:    Product is Product1 ID is 1
    D/DBINFO:    Product is Product2 ID is 2
    D/DBINFO:    Product is Product3 ID is 3
    

    【讨论】:

      猜你喜欢
      • 2019-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-18
      • 1970-01-01
      相关资源
      最近更新 更多