Ошибка комнаты: в столбцах, возвращаемых запросом, нет полей

Ошибка комнаты: в столбцах, возвращаемых запросом, нет полей

Сделал скрин как на картинке.

Как видите, Set information items находятся в red box.

Я хочу сохранить эти данные в Room DB.

red box состоит из Workout Class, а blue box (WorkoutSetInfo class) входит в него.

Я просто хочу получить список set information из комнаты.

Но я написал запрос, чтобы получить список set information, Я получил следующую ошибку:

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()

Было несколько подобных вопросов, но я до сих пор не смог их решить. Как я могу получить только список установленной информации?


Информация о тренировках

data class WorkoutSetInfo(
    val id: String = UUID.randomUUID().toString(), // For comparison in DiffUtil.
    val set: Int,
    val weight: String = "",
    val reps: String = ""
)

Тренировка

@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
interface WorkoutDao {
    @Query("SELECT sets FROM Workout")
    fun getWorkoutSetInfoList() : LiveData<List<WorkoutSetInfo>>

    @Insert
    fun insert(workout: Workout)
}

Репозиторий

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)
        }
    }
}

ОБНОВЛЕНО

class Converter {
    @TypeConverter
    fun listToJson(value: List<WorkoutSetInfo>) : String {
        return Gson().toJson(value)
    }

    @TypeConverter
    fun jsonToList(value: String) : List<WorkoutSetInfo> {
        return Gson().fromJson(value, Array<WorkoutSetInfo>::class.java).toList()
    }
}
0
0
64
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы пытаетесь сохранить список сложных объектов в столбце. Комната не знает, как это сохранить.

var sets: List<WorkoutSetInfo> = emptyList() <-- это сложно

Помните, что комната — это просто sqlite внизу, а ваши объекты представляют собой таблицы. Sqlite распознает базовые типы, но по умолчанию не может хранить список сложных объектов. Вы можете изучить ТипПреобразователи в качестве решения, если хотите сохранить этот объект в той же таблице.

См. ниже реляционное решение, в котором используются отдельные таблицы:

Здесь вы ищете отношение один ко многим. Один Workout может иметь один или несколько WorkoutSetInfo

В мире реляционных баз данных вы можете представить это, создав отдельную таблицу для WorkoutSetInfo и используя идентификатор из id работы для создания отношения.

@Entity
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
)

После этого вы можете либо написать запрос на соединение, либо использовать объект данных для запроса, как определено здесь.

У вас может быть что-то вроде этого:

data class WorkoutWithSets(
    @Embedded val workout: Workout,
    @Relation(
        parentColumn = "id",
        entityColumn = "workoutId"
    )
    val sets: List<WorkoutSetInfo>
)

И используйте что-то вроде этого, чтобы запросить его

    @Transaction
    @Query("SELECT * FROM Workout WHERE id = :workoutId")
    fun getWorkoutWithSets(workoutId: String) : LiveData<WorkoutWithSets>

Это даст тренировку для данного идентификатора вместе со всеми наборами, которые соответствуют этому идентификатору тренировки в таблице наборов.

Вы говорите, что для этого должно быть два tables из Workout и WorkoutSetInfo, а не просто использовать одну таблицу под названием Workout?

ybybyb 06.04.2022 18:36

Да, WorkoutSetInfo должна быть отдельной таблицей и содержать столбец для идентификатора тренировки. Затем в своем запросе вы должны использовать столбец trainingId, чтобы получить все WorkoutSetInfo, связанные с данной тренировкой.

Naveed 06.04.2022 19:34

Тогда должны существовать две таблицы, Workout и WorkoutSetInfo, WorkoutSetInfo должна содержать Workout Id, а к WorkoutSetInfo Table нужно обращаться с помощью Workout Id, верно?

ybybyb 06.04.2022 19:56

Да, если вы посмотрите на мой пример запроса выше, он даст вам то, что вам нужно. Кроме того, убедитесь, что WorkoutSetInfo является сущностью (также показанной в ответе), которая сообщит Room создать для нее таблицу.

Naveed 06.04.2022 19:59

здорово. Но у меня есть вопрос. Ссылка, на которую вы ответили, показывала one-to-many relationship. Но поскольку это WorkoutSetInfo для Workout, разве это не должны быть one-to-one отношения? (one Workout table и one WorkoutSetInfo table)

ybybyb 06.04.2022 20:04

Это одна WorkoutSetInfo таблица, но эта таблица может содержать несколько записей для одной тренировки. Одна вещь, о которой не упоминалось, это то, что вы должны убедиться, что всякий раз, когда вы вставляете в свою таблицу тренировок, вы также вставляете соответствующие сеансы тренировок в свою таблицу WorkoutSetInfo.

Naveed 06.04.2022 20:25

Были ли отношения основаны на tuple, а не на table-to-table? И я не правильно понял, что каждый раз, когда я вставляю его в workout table, мне нужно вставлять workout session и в WorkoutSetInfo table. Вы хотите сказать, что при вставке кортежа в Workout как минимум one tuple также должен быть вставлен в WorkoutSetInfo?

ybybyb 06.04.2022 20:34

Давайте продолжить обсуждение в чате.

Naveed 06.04.2022 20:41

ок..я вышел из дополнительного чата

ybybyb 06.04.2022 21:04

Хорошо.. Но я уже использую TypeConverter и получаю сообщение об ошибке. не знаю где проблема..

ybybyb 06.04.2022 22:21

Я бы порекомендовал задать еще один вопрос о TypeConverter и перечислить конкретно, так как у меня может не быть времени, чтобы следить за этим.

Naveed 07.04.2022 17:45

в настоящее время ваша опубликованная ошибка говорит о том, что набор не найден в выборе

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 = ""
)

но как ответ Навида, вы должны использовать typeConvertor или решить эту проблему с типом реляционной базы данных без реализации этого преобразователя типов или комнаты реляционной структуры вы получите ошибку

Я уже реализовал TypeConverter (см. update) Я получил эту ошибку при создании TypeConverter. Кстати, вы говорите, что можете создать table, не используя TypeConverter?

ybybyb 06.04.2022 18:54

TypeConverter Or Two Table — варианты для вашего случая. Могу ли я узнать, есть ли у вас такая же ошибка после внедрения TypeConverter? Вы пытались сделать set обнуляемым?

gulab patel 06.04.2022 20:02

Обновлен класс TypeConverter до исходного плаката. Я использовал TypeConverter и получил ошибку. И я не собираюсь устанавливать set на null.

ybybyb 06.04.2022 20:08

Другие вопросы по теме