Сбой ограничения NOT NULL, когда я хочу сохранить данные в комнате - PullRequest
0 голосов
/ 19 апреля 2019

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

2019-04-19 13:44:44.768 8549-8549/com.sample.android.superhero E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.sample.android.superhero, PID: 8549
    android.database.sqlite.SQLiteConstraintException: NOT NULL constraint failed: heroes.power_id (code 1299)
    #################################################################
    Error Code : 1299 (SQLITE_CONSTRAINT_NOTNULL)
    Caused By : Abort due to constraint violation.
        (NOT NULL constraint failed: heroes.power_id (code 1299))
    #################################################################
        at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
        at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:953)
        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.sample.android.superhero.data.source.local.HeroDao_Impl.insertHero(HeroDao_Impl.java:189)
        at com.sample.android.superhero.data.source.local.SuperHeroLocalDataSource$saveHero$2.invokeSuspend(SuperHeroLocalDataSource.kt:27)
        at com.sample.android.superhero.data.source.local.SuperHeroLocalDataSource$saveHero$2.invoke(Unknown Source:10)
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:91)
        at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:146)
        at kotlinx.coroutines.BuildersKt.withContext(Unknown Source:1)
        at com.sample.android.superhero.data.source.local.SuperHeroLocalDataSource.saveHero(SuperHeroLocalDataSource.kt:26)
        at com.sample.android.superhero.data.source.SuperHeroRepository.refreshLocalDataSource(SuperHeroRepository.kt:55)
        at com.sample.android.superhero.data.source.SuperHeroRepository.getHeroesFromRemoteDataSource(SuperHeroRepository.kt:45)
        at com.sample.android.superhero.data.source.SuperHeroRepository$getHeroesFromRemoteDataSource$1.invokeSuspend(Unknown Source:12)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.ResumeModeKt.resumeUninterceptedMode(ResumeMode.kt:46)
        at kotlinx.coroutines.internal.ScopeCoroutine.onCompletionInternal$kotlinx_coroutines_core(Scopes.kt:28)
        at kotlinx.coroutines.JobSupport.completeStateFinalization(JobSupport.kt:305)
        at kotlinx.coroutines.JobSupport.tryFinalizeSimpleState(JobSupport.kt:264)
        at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:762)
        at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:742)
        at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:117)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
        at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742)

Модель моего героя выглядит следующим образом:

@Entity(tableName = "heroes")
class Hero(
    @PrimaryKey @ColumnInfo(name = "entryid")
    val id: String,
    val name: String,
    @Embedded(prefix = "power_")
    val power: Powerstates,
    @Embedded(prefix = "bio_")
    val bio: Biography,
    @Embedded(prefix = "appearance_")
    val appearance: Appearance,
    @Embedded(prefix = "work_")
    val work: Work,
    @Embedded
    val image: Image
)

Вот моя модель Power:

@Entity(
    tableName = "powerstates",
    foreignKeys = [
        ForeignKey(
            entity = Hero::class,
            parentColumns = ["entryid"],
            childColumns = ["heroId"],
            onDelete = ForeignKey.CASCADE
        )], indices = [Index("heroId")]
)
class Powerstates(
    @PrimaryKey(autoGenerate = true)
    val id: Int,
    val heroId: Int,
    val intelligence: Int,
    val strength: Int,
    val speed: Int,
    val power: Int,
    val combat: Int
)

А вот логика сохранения и извлечения данных:

override suspend fun getHeroes(query: String): Result<List<Hero>> {
        return if (cacheIsDirty) {
            // If the cache is dirty we need to fetch new data from the network.
            getHeroesFromRemoteDataSource(query)
        } else {
            // Query the local storage if available. If not, query the network.
            when (val result = localDataSource.getHeroes(query)) {
                is Result.Success -> Result.Success(result.data)
                is Result.Error -> getHeroesFromRemoteDataSource(query)
            }
        }
    }

    private suspend fun getHeroesFromRemoteDataSource(query: String): Result<List<Hero>> {
        return when (val result = remoteDataSource.getHeroes(query)) {
            is Result.Success -> {
                refreshLocalDataSource(result.data)
                Result.Success(result.data)
            }
            is Result.Error -> Result.Error(result.exception)
        }
    }

    private suspend fun refreshLocalDataSource(heroes: List<Hero>) {
        localDataSource.deleteAllHeroes()
        for (hero in heroes) {
            localDataSource.saveHero(hero)
        }
    }

Я попробовал следующее решение: добавить уникальное ограничение в базе данных комнаты в несколько столбцов Но я получил ту же ошибку.

А вот и мой Dao:

@Dao
interface HeroDao {

    @Query("SELECT * FROM Heroes WHERE name LIKE :query")
    fun getHeroes(query: String): List<Hero>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertHero(hero: Hero)
}

1 Ответ

0 голосов
/ 19 апреля 2019

Вы используете Powerstates как @Embedded объект, а не отдельную сущность. Итак, удалите @PrimaryKey и @Entity из Powerstates вместе с (по-видимому) ненужными столбцами. Вы должны получить:

class Powerstates(
    val intelligence: Int,
    val strength: Int,
    val speed: Int,
    val power: Int,
    val combat: Int
)
...