问题
I am trying to save a list of custom data types in room database, actually, I want one of the column should contain list of all transactions show that I don't have to two tables.
account.kt
@Entity(tableName = "account_table")
data class account(
@ColumnInfo(name="name")
val name:String,
@ColumnInfo(name="transaction")
val transactions:List<transaction>
){
@PrimaryKey(autoGenerate = true)@ColumnInfo(name="account_id")
val accountId:Int=0
}
transaction.kt
data class transaction(
val amount:Float,
val description:String,
val date:String
)
Now when I am running the code I get an error
error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
private final java.util.List<com.example.ledger.Database.transaction> transactions = null;
^D:\flutterProjects\Ledger\app\build\tmp\kapt3\stubs\debug\com\example\ledger\Database\account.java:10: error: Cannot find setter for field.
private final int accountId = 0;
D:\flutterProjects\Ledger\app\build\tmp\kapt3\stubs\debug\com\example\ledger\Database\accountsDao.java:19: warning: The query returns some columns [account_id, name, transaction] which are not used by com.example.ledger.Database.transaction. You can use @ColumnInfo annotation on the fields to specify the mapping. com.example.ledger.Database.transaction has some fields [amount, description, date] which are not returned by the query. If they are not supposed to be read from the result, you can mark them with @Ignore annotation. You can suppress this warning by annotating the method with @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH). Columns returned by the query: account_id, name, transaction. Fields in com.example.ledger.Database.transaction: amount, description, date.
public abstract java.util.List<com.example.ledger.Database.transaction> getTransaction(int id);
^D:\flutterProjects\Ledger\app\build\tmp\kapt3\stubs\debug\com\example\ledger\Database\accountsDao.java:19: error: The columns returned by the query does not have the fields [amount,description,date] in com.example.ledger.Database.transaction even though they are annotated as non-null or primitive. Columns returned by the query: [account_id,name,transaction]
public abstract java.util.List<com.example.ledger.Database.transaction> getTransaction(int id);
^[WARN] Incremental annotation processing requested, but support is disabled because the following processors are not incremental: androidx.room.RoomProcessor (DYNAMIC).
EDIT
accountDao.kt
@Dao
interface accountsDao {
@Insert
fun Insert(account: account)
@Delete
fun delete(account: account)
@Query("SELECT * FROM account_table where account_id = :id ")
fun getTransaction(id:Int):List<transaction>
}
accountDatabase
@Database(entities = [account::class], version = 1, exportSchema = false)
abstract class accountsDatabase : RoomDatabase() {
abstract val accountdao: accountsDao
companion object {
@Volatile
private var INSTANCE: accountsDatabase? = null
fun getInstance(context: Context): accountsDatabase? {
synchronized(this) {
// Copy the current value of INSTANCE to a local variable so Kotlin can smart cast.
// Smart cast is only available to local variables.
var instance = INSTANCE
// If instance is `null` make a new database instance.
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
accountsDatabase::class.java,
"saccount_history_database"
)
.fallbackToDestructiveMigration()
.build()
// Assign INSTANCE to the newly created database.
INSTANCE = instance
}
// Return instance; smart cast to be non-null.
return instance
}
}
}
}
I feel there would some code of type convertor in Dao
file because I am accessing List<transaction>
回答1:
For example, lists, models, model list etc. When you want to store some special type objects, such as in the database, you can use Type Converters. Converts your custom object type to a type known for database types. This is the most useful feature of the Room persistent library.
account.kt:
@Entity(tableName = "account_table")
data class account(
@PrimaryKey(autoGenerate = true)@ColumnInfo(name="account_id")
val accountId:Int=0,
@ColumnInfo(name="name")
val name:String,
@TypeConverters(Converters::class)
@ColumnInfo(name="transaction")
val transactions:List<transaction>
)
Converters.kt:
class Converters {
@TypeConverter
fun fromTransactionList(transaction: List<transaction?>?): String? {
if (transaction == null) {
return null
}
val gson = Gson()
val type: Type = object : TypeToken<List<transaction?>?>() {}.type
return gson.toJson(transaction, type)
}
@TypeConverter
fun toTransactionList(transactionString: String?): List<transaction>? {
if (transactionString == null) {
return null
}
val gson = Gson()
val type =
object : TypeToken<List<transaction?>?>() {}.type
return gson.fromJson<List<transaction>>(transactionString, type)
}
}
You can add like this:
@Database(entities = [account::class], version = 1, exportSchema = false)
@TypeConverters(Converters::class)
abstract class accountsDatabase : RoomDatabase()
And interface accountsDao:
@Query("SELECT * FROM account_table where account_id = :id ")
fun getTransaction(id:Int):List<account>
using:
GlobalScope.launch {
val db = accountsDatabase.getInstance(applicationContext)
val accounts = db.accountDao().getTransaction(your_id)
val transactions = accounts[position].transactions
transactions?.forEach {
Log.d("Transaction Description" ,it.description)
}
}
来源:https://stackoverflow.com/questions/61461954/how-to-fix-the-error-while-saving-list-of-custom-data-types-in-room-database