Search code examples
androidkotlinandroid-jetpack-composeandroid-room

error: Type of the parameter must be a class annotated with @Entity or a collection/array of it. java.lang.String tocd);


I was developing sme regular room app where I try to keep same data into a localdatabase using room. I'm getting the following error:

error: Type of the parameter must be a class annotated with @Entity or a collection/array of it.
    java.lang.String tocd);
                     ^

Regarding my LocaDatabase class is this:

@Database(entities = [SessionData::class], version = 1, exportSchema = true)
abstract class LocalDatabase : RoomDatabase() {

    abstract fun dao(): CepsaDAO

}

My data class model:

@Entity(tableName = Constants.DB_NAME)
data class SessionData (
    @PrimaryKey(autoGenerate = false) val tcod: String,
    @ColumnInfo(name = "sessionToken") val sessionToken: String,
)

And my DAO:

@Dao
interface CepsaDAO {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertTocd(tocd: String):Long   //This method rise the error 

    @Query("SELECT tcod FROM ${Constants.DB_NAME}")
    fun getTocd():String?

    @Query("SELECT sessionToken FROM ${Constants.DB_NAME} WHERE tcod=:tocd")
    fun getSessionData(tocd:String): String?

    @Query("DELETE FROM ${Constants.DB_NAME} WHERE sessionToken=:token")
    fun deleteSessionId(token: String):Int
}

And in order to instanciate i'm using dagger plugin:

@InstallIn(SingletonComponent::class)
@Module
class LocalModule {

    @Provides
    @Singleton
    fun provideDB(@ApplicationContext context: Context): LocalDatabase {
        return Room.databaseBuilder(
            context.applicationContext,
            LocalDatabase::class.java,
            Constants.DB_NAME
        ).build()
    }
}

@ActivityRetainedScoped
class LocalDatabaseUseCase @Inject constructor(@ApplicationContext val context: Context) {

    @Inject
    lateinit var db : LocalDatabase

... Some code
}

So I see some solution in stackoverflow and github forums, like downground the kotlin version or the upgrade the room version, but doesn't work.

Here is my build.gralde(app):

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'kotlin-kapt'
    id 'dagger.hilt.android.plugin'
    id 'org.jetbrains.kotlin.plugin.serialization'
}

dependencies{

kotlin_version=1.8.10
kotlin_serialization=1.5.0
core_ktx_version=1.10.1
room_version=2.5.0

implementation "androidx.core:core-ktx:$core_ktx_version"
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
    implementation 'androidx.activity:activity-compose:1.7.2'
    implementation platform('androidx.compose:compose-bom:2022.10.00')
    implementation 'androidx.compose.ui:ui'
    implementation 'androidx.compose.ui:ui-graphics'
    implementation 'androidx.compose.ui:ui-tooling-preview'
    implementation 'androidx.compose.material3:material3'
    implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialization"

//Room libraries
    implementation "androidx.room:room-runtime:$room_version"
    kapt "androidx.room:room-compiler:$room_version"

    // To use Kotlin annotation processing tool (kapt)
    implementation "androidx.room:room-ktx:$room_version"
}

So, what am I missing?

Thanks in advance !


Solution

  • You have:-

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertTocd(tocd: String):Long   //This method rise the error 
    

    The insertTocd function is trying/saying to insert into the table that is defined via the String class. The kotlin String class does not have the @Entity annotation. Obviously it never would or could. It is part of Kotlin.

    When you insert into the database you insert data into the column(s) of a table table. Room determines the table(s) via the classes specified in the entities parameter of the @Database annotation. The columns for a table are ascertained according to the fields of the @Entity annotated class(es).

    You have a single class so defined according to @Database(entities = [SessionData::class], version = 1, exportSchema = true) as such you can only insert data into the Constants.DB_NAME table. When using the convenience @Insert then the object type passed to the function must be an @Entity annotated class that is defined via the entities parameter of the @Database annotation.

    It would appear that you are trying to insert a row into the table just using the tcod value.

    What you could do is use an @Query to do the insert e.g.

    @Query("INSERT OR REPLACE INTO ${Constants.DB_NAME} VALUES(:tcod,'whatever would be a suitable default value');")
    fun insertTocd(tcod: String)
    
    • note this would not return a value

    Alternately and perhaps more likely what you want, you could use something like:-

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insert(sessionData: SessionData): Long
    
    fun insertTocd(tcod: String): Long {
        return insert(SessionData(tcod,"whatever would be a suitable default value")
    } 
    
    • note this would return a value, it would be the rowid of the inserted row. rowid is a special column, that always exists for tables (when using Room). If the row could not be inserted then the value would be -1.

    • both cases whatever would be a suitable default value could be any value but not null as the type String will have a NOT NULL constraint applied.