如何使用 Room DAO 访问数据以从多个表中检索数据

How to accessing data using Room DAOs to retrieve data from multiple tables

我很努力但没有结果,我想获得关于产品的所有信息,除了类别名称和单位名称,因为我想在里面显示所有这些信息 my adapter 最好的做法是什么,请检查我的代码。

如何编写查询以访问多个表中的数据。我需要定义哪种类型的 class 来涵盖所有这些数据。

@Entity(tableName = "product")
data class Product(
    @PrimaryKey(autoGenerate = true)
    val product_id: Int,

    val name: String,
    val sellPrice: Double,
    val barcode: String?,
    val buyPrice: Double?,
    val quantity: Double?,
    val packing: Double?,
    val reducePrice: Double?,
    val description: String?,

    val fk_category: Int?,
    val fk_unit: Int?
)

@Entity(tableName = "category")
data class Category(
    @PrimaryKey(autoGenerate = true)
    val category_id: Int,

    val name: String
)

@Entity(tableName = "unit")
data class Unit(
    @PrimaryKey(autoGenerate = true)
    val unit_id: Int,

    val name: String
)

data class ProductAndCategory(
    @Embedded
    val category: Category,
    @Relation(
        parentColumn = "category_id",
        entityColumn = "fk_category"
    )
    val product: Product
)

data class ProductAndUnit(
    @Embedded
    val unit: Unit,
    @Relation(
        parentColumn = "unit_id",
        entityColumn = "fk_unit"
    )
    val product: Product
)

@Dao
interface ProductDao {

    @Query("SELECT * FROM product")
    fun getAllProducts(): LiveData<List<Product>>

    @Transaction
    @Query("SELECT * FROM product INNER JOIN category on product.fk_category = category.category_id")
    fun getAllProductAndCategory(): LiveData<List<ProductAndCategory>>

    @Query("SELECT * FROM product WHERE product_id = :productID")
    suspend fun getProduct(productID: Int): List<Product>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertProduct(product: Product)

    @Update
    suspend fun updateProduct(product: Product)

    @Delete
    suspend fun deleteProduct(product: Product)

    @Query("DELETE FROM product")
    suspend fun deleteAllProducts()

    @Transaction
    @Query("SELECT * FROM product INNER JOIN category on product.fk_category = category.category_id WHERE product_id= :productID")
    suspend fun getProductAndCategory(productID: Int): List<ProductAndCategory>

    @Transaction
    @Query("SELECT * FROM product INNER JOIN unit on product.fk_unit = unit.unit_id WHERE product_id= :productID")
    suspend fun getProductAndUnit(productID: Int): List<ProductAndUnit>
}

您可以通过两种方式执行此操作。

您可以嵌入产品并为类别和单位设置一个@Relation (2 @Realtion),或者您可以嵌入所有三个。

所以你可以:-

data class ProductAndCategoryAndUnit(
    @Embedded
    val product: Product,
    @Relation(entity = Category::class, parentColumn = "fk_category",entityColumn = "category_id")
    val category: Category,
    @Relation(entity = Unit::class, parentColumn = "fk_unit",entityColumn = "unit_id")
    val unit: Unit
)

类似 :-

@Query("SELECT * FROM product")
@Transaction
fun getProductAndCategoryAndUnit(): List<ProductAndCategoryAndUnit>

或交替(但请阅读注释):-

data class ProductCategoryUnit (
    @Embedded
    val product: Product,
    @Embedded
    val category: Category,
    @Embedded
    val unit: Unit
)

类似 :-

@Query("SELECT * FROM product JOIN category ON product.fk_category = category.category_id JOIN unit ON product.fk_unit = unit.unit_id")
    fun getProductCategoryUnit(): List<ProductCategoryUnit>

第二个注释

此替代方案将对所有名为 name 的 3 列产生问题(它们会产生歧义)。您可以使用 @Embedded(prefix = "?") 来消除歧义,但这需要在 SQL 中为列添加别名。一种更简单的方法是确保列名不会有歧义。这可以很容易地使用@ColumnInfo 的名称参数作为单位的示例来实现(类别需要类似的):-

@Entity(tableName = "unit")
data class Unit(
    @PrimaryKey(autoGenerate = true)
    val unit_id: Long,
    @ColumnInfo(name = "unit_name") // ADDED to disambiguate for joins
    val name: String
)
  • 注意 id 应该是 Long 而不是 Int。

两者的工作示例

根据您的代码,下面对两者进行了演示,请注意,为了方便和简洁起见,演示是在主线程上 运行,因此 LiveData 和挂起的函数已相应更改。长整数也被用于 id 而不是 Int。

使用的产品数据class:-

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

    val name: String,
    val sellPrice: Double,
    val barcode: String?,
    val buyPrice: Double?,
    val quantity: Double?,
    val packing: Double?,
    val reducePrice: Double?,
    val description: String?,
    val fk_category: Long?,
    val fk_unit: Long?
)

使用的分类数据class:-

@Entity(tableName = "category")
data class Category(
    @PrimaryKey(autoGenerate = true)
    val category_id: Long,
    @ColumnInfo(name = "category_name") // ADDED to disambiguate for joins
    val name: String
)

数据class单位和POJO一样。

用于演示的 ProductDao :-

@Dao
interface ProductDao {

    @Query("SELECT * FROM product")
    fun getAllProducts(): /*LiveData<*/List<Product>/*>*/

    /*
    @Transaction
    @Query("SELECT * FROM product INNER JOIN category on product.fk_category = category.category_id")
    fun getAllProductAndCategory(): LiveData<List<ProductAndCategory>>
    */

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun insert(unit: Unit): Long
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun insert(category: Category): Long


    @Query("SELECT * FROM product WHERE product_id = :productID")
    suspend fun getProduct(productID: Int): List<Product>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    /*suspend*/ fun insertProduct(product: Product)

    @Update
    suspend fun updateProduct(product: Product)

    @Delete
    suspend fun deleteProduct(product: Product)

    @Query("DELETE FROM product")
    suspend fun deleteAllProducts()

    /*
    @Transaction
    @Query("SELECT * FROM product INNER JOIN category on product.fk_category = category.category_id WHERE product_id= :productID")
    suspend fun getProductAndCategory(productID: Int): List<ProductAndCategory>
    */

    /*
    @Transaction
    @Query("SELECT * FROM product INNER JOIN unit on product.fk_unit = unit.unit_id WHERE product_id= :productID")
    suspend fun getProductAndUnit(productID: Int): List<ProductAndUnit>
    */

    @Query("SELECT * FROM product")
    @Transaction
    fun getProductAndCategoryAndUnit(): List<ProductAndCategoryAndUnit>

    @Query("SELECT * FROM product WHERE product_id=:productID")
    fun getProductAndCategoryAndUnitById(productID: Long): List<ProductAndCategoryAndUnit>

    @Query("SELECT * FROM product JOIN category ON product.fk_category = category.category_id JOIN unit ON product.fk_unit = unit.unit_id")
    fun getProductCategoryUnit(): List<ProductCategoryUnit>

}

TheDatabase class 是一个很好的@Database,所以不包括在内。

最后是 Activity 根据 :-

class MainActivity : AppCompatActivity() {
    lateinit var db: TheDatabase
    lateinit var dao: ProductDao
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        db = TheDatabase.getInstance(this)
        dao = db.getProductDao()

        var u1 = dao.insert(Unit(0L, "Unit1"))
        var u2 = dao.insert(Unit(0L, "Unit2"))

        var c1 = dao.insert(Category(0L,"Cat1"))
        var c2 = dao.insert(Category(0L,"Cat2"))

        dao.insertProduct(Product(0L,"Produuct1",1.1,"Barcode001",2.2,10.5,0.0,0.0,"Desc4Product1",c2,u1))
        dao.insertProduct(Product(0L,"Product2",1.1,"Barcode002",2.2,10.5,0.0,0.0,"Desc4product2",c1,u2))

        // Inserts Catergory,Unit and Product (utilising the id returned by the inserts for the category and Unit)
        dao.insertProduct(
            Product(
                0L,"" +
                        "Product3",
                1.1,"" +
                        "Barcode003",
                2.2,
                10.5,
                0.0,
                0.0,
                "Desc4Product3",
                dao.insert(Category(0L,"Cat4")),
                dao.insert(Unit(0L,"Unit4"))
            )
        )

        // Extract and Log via the @Embedded and 2 @Realtion's
        for(pcu: ProductAndCategoryAndUnit in dao.getProductAndCategoryAndUnit()) {
            Log.d("PRODUCTINFO","Product is ${pcu.product.name} .... Category is ${pcu.category.name} Unit is ${pcu.unit.name}")
        }
        // Extract and Log via the 3 @Embedded's
        for(pcu: ProductCategoryUnit in dao.getProductCategoryUnit()) {
            Log.d("PRODUCTINFO","Product is ${pcu.product.name} .... Category is ${pcu.category.name} Unit is ${pcu.unit.name}")
        }
    }
}

日志中的结果:-

D/PRODUCTINFO: Product is Produuct1 .... Category is Cat2 Unit is Unit1
D/PRODUCTINFO: Product is Product2 .... Category is Cat1 Unit is Unit2
D/PRODUCTINFO: Product is Product3 .... Category is Cat4 Unit is Unit4


D/PRODUCTINFO: Product is Produuct1 .... Category is Cat2 Unit is Unit1
D/PRODUCTINFO: Product is Product2 .... Category is Cat1 Unit is Unit2
D/PRODUCTINFO: Product is Product3 .... Category is Cat4 Unit is Unit4

即两种方法的结果是相同的。