Ошибка ограничения уникальности при попытке обновления

#android #kotlin #android-room

Вопрос:

Я пытался обновить данные базы данных номеров и получил эту ошибку. Нужно ли мне иметь уникальный идентификатор при попытке обновить элемент? Я попытался найти решение, как устранить эту ошибку, но в основном оно вращается вокруг операции ВСТАВКИ ( операция вставки работает) или решения на другом языке программирования.

Ошибка:

  android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: Plant.plant_id (code 1555 SQLITE_CONSTRAINT_PRIMARYKEY)
        at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
        at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:796)
        at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
        at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
        at androidx.sqlite.db.framework.FrameworkSQLiteStatement.executeInsert(FrameworkSQLiteStatement.java:51)
        at androidx.room.EntityInsertionAdapter.insert(EntityInsertionAdapter.java:64)
        at com.example.plantmanagement.dao.PlantOperations_Impl.insertPlant(PlantOperations_Impl.java:136)
        at com.example.plantmanagement.repository.PlantRepository.insertPlant(PlantRepository.kt:17)
        at com.example.plantmanagement.viewmodel.PlantViewModel$insertPlant$1.invokeSuspend(PlantViewModel.kt:25)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:342)
        at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30)
        at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:27)
        at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:109)
        at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:158)
        at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
        at kotlinx.coroutines.BuildersKt.launch(Unknown Source:1)
        at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:49)
        at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source:1)
        at com.example.plantmanagement.viewmodel.PlantViewModel.insertPlant(PlantViewModel.kt:24)
        at com.example.plantmanagement.activity.Edit_Plant$onCreate$2.onClick(Edit_Plant.kt:98)
        at android.view.View.performClick(View.java:6597)
        at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:992)
        at android.view.View.performClickInternal(View.java:6574)
        at android.view.View.access$3100(View.java:778)
        at android.view.View$PerformClick.run(View.java:25885)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
 

Класс сущностей:

 Entity(tableName = "Plant")
data class Plant(

        @PrimaryKey(autoGenerate = true) var plant_id:Long,
        @ColumnInfo (name="plant_name") var name: String,
        //@Embedded var type: Plant_Category,
        @ColumnInfo(name= "plant_image", typeAffinity = ColumnInfo.BLOB) var image: ByteArray,
        @ColumnInfo(name="plant_type_name") var type:String ="",
        @ColumnInfo(name="plant_type_water")var water_time: String ="",
        @ColumnInfo(name="plant_type_details")var details: String = "",


        )
 

Класс Dao:

 @Dao
interface PlantOperations {
    @Query("SELECT * FROM Plant")
    fun getAll(): Flow<List<Plant>>


    @Insert
    fun insertAll(vararg plant: Plant?)
    @Insert
    fun insertPlant(plant: Plant)
    @Query("DELETE  FROM Plant WHERE plant_id = :id")
    fun delete(id: Long)

    @Update(onConflict = OnConflictStrategy.REPLACE)
    fun updatePlant(plant: Plant)}
 

Я также убедился, что не вставляю другой идентификатор.

Я был бы благодарен за помощь.

Ответ №1:

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

 at com.example.plantmanagement.repository.PlantRepository.insertPlant(PlantRepository.kt:17)
 

поэтому, чтобы обновить запись, вам нужно вызвать updatePlant метод.

Также я не вижу никакой пользы onConflict = OnConflictStrategy.REPLACE в случае update , если вы, вероятно, захотите использовать это с вашим insert методом. поэтому обновите свои insert методы и update методы, как

 @Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertPlant(plant: Plant)

@Update
fun updatePlant(plant: Plant)
 

Комментарии:

1. Но я постараюсь на всякий случай.

2. Похоже, я случайно использовал метод вставки, а не метод обновления. Который я, хотя и использовал метод обновления, но, возможно, случайно отменил код и не увидел код, возвращающийся из метода обновления для вставки . Спасибо, что нашли время указать на это.