我尝试为我的应用建立离线支持。这是我运行应用程序时出现的异常错误:
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)
}
}
我尝试了以下解决方案:add unique constraint in room database to multiple column 但是我遇到了同样的错误。
这是我的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)
}
答案 0 :(得分:0)
您将Powerstates
用作@Embedded
对象,而不是单独的实体。因此,从@PrimaryKey
中删除@Entity
和Powerstates
,以及(显然)不必要的列。您应该结束:
class Powerstates(
val intelligence: Int,
val strength: Int,
val speed: Int,
val power: Int,
val combat: Int
)
答案 1 :(得分:0)
正如CommonsWare所述:您可能希望查看生成的Room代码(堆栈跟踪中列出的类),并查看可能出了什么问题。 – CommonsWare
最好调试生成的代码,您将获得所需的信息。就我而言,它有所帮助。