[英]Join 2 Table with Android Kotlin Room and display plain data in a single Row in RecycleView
I am experimenting with Room , Live Data and Recycler View in Android Kotlin .我正在Android Kotlin中试验Room 、 Live Data和Recycler View 。
My question is, I am trying to make an expense tracking APP, and I have 2 Table:我的问题是,我正在尝试制作一个费用跟踪应用程序,并且我有 2 个表:
I joined the table as indicated in Room documentation for 1:N relationship .我按照 Room documentation for 1:N relationship 中的指示加入了表格。
Example of my table:我的表格示例:
**Expense**
*ID = 1
expenseName = MyExpense1
expenseAmount = 100
expenseTypeID = 1*
**ExpenseType**
*ID= 1
ExpenseType= Home Expenses*
**Result expected from JOIN:**
*expenseName = MyExpense1
expenseAmount = 100
expenseType = Home Expenses*
But in this way, when I get the data for recycler view, I get a list that contain:但是通过这种方式,当我获取回收者视图的数据时,我得到一个包含以下内容的列表:
How can I have data as if **I JOINED ** the table?我怎样才能像 **I JOINED ** 表一样拥有数据? Since my **ExpenseTypeWithExpense **class contains a class and a List of class
由于我的 **ExpenseTypeWithExpense **类包含 class 和 class 的列表
Usually I use a **RecycleView **on just one table and it is easy since I have a list of my Entity Class and I can access the single instance with list[position] in my **onBindViewHolder **class通常我只在一张表上使用 **RecycleView **,这很容易,因为我有一个实体列表 Class,我可以在我的 **onBindViewHolder **类中使用列表[位置]访问单个实例
@Entity(
foreignKeys =[
ForeignKey(
entity = ExpenseType::class,
parentColumns = ["id"],
childColumns = ["expenseTypeID"]
)]
)
data class Expense (
@PrimaryKey(autoGenerate = true)
val id:Int,
val expenseName: String,
val expenseAmount: Double,
val expenseTypeID:Int
)
@Entity(tableName = "expense_type")
data class ExpenseType (
@PrimaryKey(autoGenerate = true)
val id:Int,
val expenseType: String
)
data class ExpenseTypeWithExpense (
@Embedded val expenseType: ExpenseType,
@Relation(
parentColumn ="id",
entityColumn ="id"
)
val expense: List<Expense>
)
@Dao
interface ExpenseDao {
@Insert
suspend fun insertExpense(expense: Expense)
@Insert
suspend fun insertExpenseType(expenseType:ExpenseType)
@Transaction
@Query("SELECT * FROM expense_type")
fun getExpenseWithType():LiveData<List<ExpenseTypeWithExpense>>
}
class ExpenseRepository(private val expenseDao: ExpenseDao) {
val readAllData: LiveData<List<ExpenseTypeWithExpense>> = expenseDao.getExpenseWithType()
suspend fun insertExpense(expense: Expense){
expenseDao.insertExpense(expense)
}
suspend fun insertExpenseType(expenseType: ExpenseType){
expenseDao.insertExpenseType(expenseType)
}
}
class ExpenseViewModel(application: Application):AndroidViewModel(application) {
val readAllData: LiveData<List<ExpenseTypeWithExpense>>
private val repository: ExpenseRepository
init {
val expenseDao: ExpenseDao = ExpenseDatabase.getDatabase(application).expenseDao()
repository = ExpenseRepository(expenseDao)
readAllData = expenseDao.getExpenseWithType()
}
fun insertExpense(expense: Expense){
viewModelScope.launch(Dispatchers.IO){
repository.insertExpense(expense)
}
}
fun insertExpenseType(expenseType: ExpenseType){
viewModelScope.launch(Dispatchers.IO){
repository.insertExpenseType(expenseType)
}
}
}
class ListAdapter(): RecyclerView.Adapter<ListAdapter.MyViewHolder>() {
private val expenseList = emptyList<ExpenseTypeWithExpense>()
class MyViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.custom_row, parent, false))
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = expenseList[position]
holder.itemView.findViewById<TextView>(R.id.expenseName).text =
# ** //currentItem is an instance of ExpenseTypeWithExpense and contains ExpenseType class and an Expense List**
}
override fun getItemCount(): Int {
return expenseList.size
}
}
I do not Know how to handle this...我不知道如何处理这个......
When you use @Relation
there is no actual JOIN, rather for each parent (the @Embedded) the children are obtained as a list, as you have found.当您使用
@Relation
时,没有实际的 JOIN,而是对于每个父母(@Embedded),孩子都是作为列表获得的,正如您所发现的那样。
If you want the true cartesian product then you would use a POJO without the @Relation but rather @Embeded
and the query would have the JOIN.如果您想要真正的笛卡尔积,那么您将使用不带 @Relation 的 POJO,而是使用
@Embeded
,并且查询将具有 JOIN。
eg例如
data class ExpenseTypeWithExpense (
@Embedded val expenseType: ExpenseType,
@Embedded
val expense: Expense
)
The query could then be:-然后查询可以是:-
@Query("SELECT * FROM expense_type JOIN expense ON expense_type.id = expense.expenseTypeID;")
However , as the id field is common to both and that rather than objects (ExpenseType and Expense being included in the output) You probably want the POJO to be但是,由于id字段对两者都是通用的,而不是对象(输出中包含 ExpenseType 和 Expense),您可能希望 POJO 是
:- :-
data class ExpenseTypeWithExpense (
val idOfExpenseType:Int,
val expenseType: String,
val id:Int,
val expenseName: String,
val expenseAmount: Double,
val expenseTypeID:Int
)
And the Query to (to rename the output columns so they can be assigned to the fields) as查询到(重命名 output 列,以便将它们分配给字段)为
@Query("SELECT expense_type.id AS idOfExpenseType, expense_type.expenseType, expense.* FROM expense_type JOIN expense ON expense_type.id = expense.expenseTypeID;;")
If you had expense_type as:-如果您的 expense_type 为:-
id expenseType
1 T1
2 T2
3 T3
and expense as:-费用为:-
id expenseName expenseAmount expenseTypeID
1 EXP1 100.11 1
2 EXP2 200.22 1
3 EXP3 300.33 1
4 EXP4 400.44 2
5 EXP5 500.55 2
Then the cartesian product output would be:-那么笛卡尔积 output 将是:-
which would equate to 5 ExpenseTypeWithExpense objects being returned in the LiveData<List>这相当于在 LiveData<List> 中返回 5 个 ExpenseTypeWithExpense 对象
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.