I made a screen like the image.
As you can see, the Set information items
are in the red box
.
I want to store these data in Room DB
.
The red box
is composed of Workout Class
, and the blue box
(WorkoutSetInfo class
) is included in it.
I just want to get a list of set information
from Room.
But I wrote a query to get a list of set information
,
I got the following error:
error: The columns returned by the query does not have the fields [id,set,weight,reps] in com.example.lightweight.data.db.entity.WorkoutSetInfo even though they are annotated as non-null or primitive. Columns returned by the query: [sets]
public abstract androidx.lifecycle.LiveData<java.util.List<com.example.lightweight.data.db.entity.WorkoutSetInfo>> getWorkoutSetInfoList()
There have been several similar questions to mine, but I still haven't been able to solve them. How can I get only the list of set information?
WorkoutSetInfo
data class WorkoutSetInfo(
val id: String = UUID.randomUUID().toString(), // For comparison in DiffUtil.
val set: Int,
val weight: String = "",
val reps: String = ""
)
Workout
@Entity
data class Workout(
@PrimaryKey(autoGenerate = true)
val id: Int,
val title: String = "",
val unit: String = "kg",
val memo: String = "",
var sets: List<WorkoutSetInfo> = emptyList()
)
DAO
@Dao
interface WorkoutDao {
@Query("SELECT sets FROM Workout")
fun getWorkoutSetInfoList() : LiveData<List<WorkoutSetInfo>>
@Insert
fun insert(workout: Workout)
}
Repository
class WorkoutRepository(private val workoutDao : WorkoutDao, title: String) {
val workout = Workout(0, title)
var setInfoList : ArrayList<WorkoutSetInfo> = arrayListOf()
val _items: LiveData<List<WorkoutSetInfo>> = workoutDao.getWorkoutSetInfoList()
fun add(item: WorkoutSetInfo) {
setInfoList.add(item)
workout.sets = setInfoList
workoutDao.insert(workout)
}
}
ViewModel
class DetailViewModel(application: Application, title: String) : ViewModel() {
private val repository: WorkoutRepository
private lateinit var _items: LiveData<List<WorkoutSetInfo>>
val items = _items
private val list: List<WorkoutSetInfo>
get() = _items.value ?: emptyList()
init {
val workoutDao = DetailDatabase.getDatabase(application)!!.workoutDao()
repository = WorkoutRepository(workoutDao, title)
_items = repository._items
}
fun addDetail() {
viewModelScope.launch(Dispatchers.IO){
val item = WorkoutSetInfo(set = list.size 1)
repository.add(item)
}
}
}
CodePudding user response:
You are trying to save a list of complex object in a column. Room does not know how to save that.
var sets: List<WorkoutSetInfo> = emptyList()
<-- this is complex
Remember room is just sqlite underneath and your entities represent tables. Sqlite recognizes basic types but storing a list of complex objects is not something it can do by default. You can explore TypeConverters as a solution if you want to save this object in the same table.
See below for a relational solution that utilizes separate tables:
What you are looking for here is a one-to-many relation. A single Workout
can have one or more WorkoutSetInfo
In the world of relational databases, you can represent this by having a separate table for WorkoutSetInfo
and use the id from id
of the work out to create a relation.
data class WorkoutSetInfo(
val id: String = UUID.randomUUID().toString(), // For comparison in DiffUtil.
val set: Int,
val weight: String = "",
val reps: String = "",
val workoutId: String // <-- this is the id of the workout that this set is associated with
)
Once you have that you can either write a join query or use a data object to query as defined here
You can have something like this:
data class WorkoutWithSets(
@Embedded val workout: Workout,
@Relation(
parentColumn = "id",
entityColumn = "workoutId"
)
val sets: List<WorkoutSetInfo>
)
And use something like this to query it
@Transaction
@Query("SELECT * FROM Workout WHERE id = :workoutId")
fun getWorkoutWithSets(workoutId: String) : LiveData<WorkoutWithSets>
This will give the workout for the given id along with all the sets that match that workout id in the set table.
CodePudding user response:
currently your posted error is telling that set is not found in selection
data class WorkoutSetInfo(
val id: String = UUID.randomUUID().toString(), // For comparison in DiffUtil.
val set: Int,//Add Any value or make it nullable here for get temp rid of this error
val weight: String = "",
val reps: String = ""
)
but As Naveeds Answer, you have to use typeConvertor or solve this problem with relational database type without implementing this typeconvertor or relational structure room will give you error