[英]Unable to insert data to Room database
我正在尝试将值插入房间数据库,但它不起作用,我检查了数据库,但没有创建表。 我在 java 中创建了数据库、DAO 和存储库,并在 MainActivity Kotlin class 中的协程中调用插入 dao。
道
@Insert
public void addExpense(List<Expenses> exp);
资料库
public class Repository {
private ExpensesDao expensesDao;
private SubscriptionsDao subscriptionsDao;
private static AppDatabase db;
public Repository(Context context) {
initDb(context);
expensesDao = db.expensesDao();
subscriptionsDao = db.subscriptionsDao();
}
private static void initDb(Context context) {
if (db == null) {
db = Room.databaseBuilder(
context,
AppDatabase.class, "local_db"
)
.addMigrations(AppDatabase.DbMigration)
.build();
}
}
public void addExpense(List<Expenses> exp) {
expensesDao.addExpense(exp);
}
}
主活动.kt
class MainActivity : AppCompatActivity() {
private var firstRun = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val db = Repository(applicationContext)
var spacesList: List<String> = listOf("No Spaces Found")
var expList: List<Expenses> = listOf(
Expenses("dummy", LocalDate.now().toString(), 12.22, "dummy1"),
Expenses("dummy", LocalDate.now().toString(), 12.22, "dummy2"),
Expenses("dummy", LocalDate.now().toString(), 13.22, "dummy3"),
Expenses("dummy", LocalDate.now().toString(), 14.22, "dummy4"),
Expenses("dummy", LocalDate.now().toString(), 15.22, "dummy5"),
Expenses("dummy", LocalDate.now().toString(), 16.22, "dummy6")
)
CoroutineScope(Dispatchers.IO).launch {
// the insert call
val x = db.addExpense(expList)
println("-->> "+x.toString())
}
val tempSpacesList = db.getAllSpaces().value
if (tempSpacesList?.isEmpty() == true) {
spacesList = tempSpacesList
}
}
}
编辑
@Entity
public class Expenses {
public Expenses(String space, String date, double amount, String description) {
this.uid = uid;
this.space = space;
this.date = date;
this.amount = amount;
this.description = description;
}
@PrimaryKey(autoGenerate = true)
int uid;
@ColumnInfo(name = "space")
String space;
@ColumnInfo(name = "date")
String date;
@ColumnInfo(name = "amount")
double amount;
@ColumnInfo(name = "description")
String description;
}
Logcat(这里不多..)
15:11:55.340 E Could not remove dir '/data/data/org.android.app/code_cache/.ll/': No such file or directory
您的代码(较少使用 Subscirptions 和 getAllApaces)即 MainActivity 是:-
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val db = Repository(applicationContext)
var spacesList: List<String> = listOf("No Spaces Found")
var expList: List<Expenses> = listOf(
Expenses("dummy", LocalDate.now().toString(), 12.22, "dummy1"),
Expenses("dummy", LocalDate.now().toString(), 12.22, "dummy2"),
Expenses("dummy", LocalDate.now().toString(), 13.22, "dummy3"),
Expenses("dummy", LocalDate.now().toString(), 14.22, "dummy4"),
Expenses("dummy", LocalDate.now().toString(), 15.22, "dummy5"),
Expenses("dummy", LocalDate.now().toString(), 16.22, "dummy6")
)
CoroutineScope(Dispatchers.IO).launch {
// the insert call
val x = db.addExpense(expList)
println("-->> "+x.toString())
}
/*
val tempSpacesList = db.getAllSpaces().value
if (tempSpacesList?.isEmpty() == true) {
spacesList = tempSpacesList
}
*/
}
}
与 AppInspection 一起显示:-
也许您的问题在于您如何查看表是否存在。 您是否使用过 App Inspection(并等待它开展业务)?
做出了以下假设:
:-
@Database(entities = {Expenses.class}, exportSchema = false, version = 1)
abstract class AppDatabase extends RoomDatabase {
abstract ExpensesDao expensesDao();
}
:-
kapt 'androidx.room:room-compiler:2.5.0'
implementation 'androidx.room:room-ktx:2.5.0'
implementation 'androidx.room:room-runtime:2.5.0'
annotationProcessor 'androidx.room:room-compiler:2.5.0'
:-
id 'kotlin-kapt'
这是使用 insert dao 的正确方法吗?
是的
我可以在此实施上改进什么?
您可以消除autoGenerate=true
的低效使用,它实际上不会导致自动生成,而是添加AUTOINCREMENT
关键字,但接受 0 不是 0,而是将 0 的值解释为无值,从而生成值。
那就是你可以使用:-
@Entity
public class Expenses {
public Expenses(String space, String date, double amount, String description) {
this.space = space;
this.date = date;
this.amount = amount;
this.description = description;
}
@PrimaryKey
Integer uid= null; /* <<<<<<<< now Inetger (object not primitive) so can be null
....
AUTOINCREMENT又名autoGenerate=true
引入了一个约束(规则),强制生成的值大于任何曾经使用过的值和每个表的基础。 如果没有 AUTOINCRMENT,生成的值将比当前最大值大 1,从而允许重用已删除的行的值。
效率低下是为了知道已存在的行的值 SQLite 创建了一个名为 sqlite_sequence 的表,该表存储最高分配的值。 每当生成值时都需要读取和更新此附加表,因此文档说
AUTOINCREMENT 关键字强加额外的 CPU、memory、磁盘空间和磁盘 I/O 开销,如果不是严格需要,应避免使用。 通常不需要。
这是使用autoGenerate=true
时的所有表格(再次使用 App Inspection)
然后建议删除autoGenerate=true
另一个改进是,对于此类列(INTEGER 列类型和 PRIMARY KEY),使用 long 或 Long 代替 int 或 Integer 更正确,因此在插入时如果不提供值,则生成一个值。 该值可以超过 int/Integer 可以容纳的值(最大 2147483647),因为 SQLite 存储最多 64 位签名的 integer(9223372036854775807)。
此外,实际生成的值可能非常有用,因为它唯一标识行(尤其是在使用表之间的关系时)。 您可以在插入一行或多行时获取此值,但它将作为 long 而不是 Int 返回。 您还可以在再次插入多行而不是整数时检索值数组。 所以你可以: -
@Insert
public long[] addExpense(List<Expenses> exp); /* or Long[] */
@Insert(onConflict = OnConflictStrategy.IGNORE)
那么如果一行由于可忽略的冲突(例如重复)而被忽略,那么该插入的值将为 -1。根据建议的更改,App Inspection 显示:-
即没有明显的区别,数据已添加(应用程序已卸载删除整个数据库)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.