如何使用 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
即两种方法的结果是相同的。
我很努力但没有结果,我想获得关于产品的所有信息,除了类别名称和单位名称,因为我想在里面显示所有这些信息 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
即两种方法的结果是相同的。