- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想了解如何将 Room 与关系表一起使用。我创建了一个 Job 模型,它有一个位置列表,因此需要 Job 和 Location 对象之间的一对多关系。为此,我创建了一个 JobWrapper 数据类来保存作业和位置。但是,在构建时出现以下错误:
The class must be either @Entity or @DatabaseView. -java.util.Collectionerror: Entities and POJOs must have a usablepublic constructor. You can have an empty constructor or a constructorwhose parameters match the fields (by name and type). -java.util.Collection \models\JobWrapper.java:12: error: Cannot findthe child entity column
parentId
in java.util.Collection.Options:private java.util.Collection<models.Location> locations;public final class JobWrapper {^ Tried the following constructors but they failed to match:
JobWrapper(models.Job,java.util.Collection<models.Location>)-> [param:job -> matched field:job, param:locations -> matched field:unmatched] models\JobWrapper.java:9:error: Cannot find setter for field.
我注意到它至少找不到位置表。但是,我不知道如何处理这个问题。从数据库读取时没有出现问题 - 它第一次出现是在我尝试使用 JobDAO 将数据放入数据库时出现的。我已经花了一天时间尝试解决它,因此正在寻找解决方案或关于如何解决它的一些建议。
注意:我一直遵循以下指南:
以下是我项目中的一些相关代码 fragment :
JobWrapper.kt
data class JobWrapper(
@Embedded val job: Job,
@Relation(
parentColumn = "jobid",
entityColumn = "parentId"
) var locations : Collection<Location>
)
工作
@Entity
data class Job (
@PrimaryKey
@NonNull
var jobid : String,
@NonNull
@ColumnInfo(name = "job_status")
var status : JobStatus,
@NonNull
@SerializedName("createdByAuth0Id")
var creator : String,
@SerializedName("note")
var note : String?,
@NonNull
var organisationId : String,
@NonNull
var type : JobType,
@SerializedName("atCustomerId")
@NonNull
@ColumnInfo(name = "working_at_customer_id")
var workingAtCustomerId : String,
@SerializedName("toCustomerId")
@NonNull
@ColumnInfo(name = "working_to_customer_id")
var workingToCustomerId : String,
)
JobStatus.kt
enum class JobStatus {
CREATED,
READY,
IN_PROGRESS,
FINISHED
}
Location.kt
@Entity
data class Location (
@PrimaryKey(autoGenerate = true)
var entityId: Long,
@NonNull
var parentId: String,
@NonNull
var locationId: String,
@NonNull
var type: String
) {
constructor() : this(0, "", "", "")
}
JobDao.kt
@Dao
interface JobDAO {
@Transaction
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(job: JobWrapper)
@Transaction
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(jobs: List<JobWrapper>)
@Transaction
@Update
fun update(job: JobWrapper)
@Transaction
@Delete
fun delete(job: JobWrapper)
@Transaction
@Query("DELETE FROM Job")
fun deleteAll()
@Transaction
@Query("SELECT * FROM Job")
fun getAll(): LiveData<List<JobWrapper>>
}
最佳答案
正如 Kraigolas 所指出的,您只能直接使用 JobWrapper 来提取您需要通过实际的底层实体插入/删除/更新的数据。
考虑以下问题
(与 Kraigolas 的解决方案不同,扩展功能在 JobDao 中而不是在存储库中(swings 和 roundabouts 争论哪个更好))
测试注意事项为了简洁和方便,我做了一些更改,因此您必须修改以适应。
JobDao
@Dao
interface JobDAO {
/* Core/Underlying DAO's */
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(job: Job): Long
@Insert()
fun insert(location: List<Location>): List<Long>
@Transaction
@Delete
fun delete(location: List<Location>)
@Delete
fun delete(job: Job)
@Update
fun update(job: Job)
@Update
fun update(location: List<Location>)
@Transaction
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(job: JobWrapper): Long {
val rv =insert(job.job)
insert(job.locations)
return rv
}
@Transaction
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(jobs: List<JobWrapper>) {
for (jw: JobWrapper in jobs) {
insert(jw)
}
}
@Transaction
@Update
fun update(job: JobWrapper) {
update(job.locations)
update(job.job)
}
/* Delete according to JobWrapper allowing optional deletion of locations */
@Transaction
@Delete
fun delete(job: JobWrapper, deleteChildLocations: Boolean) {
if (deleteChildLocations) {
delete(job.locations)
}
delete(job.job)
}
/* will orphan locations as is */
/* Note using Foreign Keys in Location (to Job) with ON DELETE CASCADE */
@Transaction
@Query("DELETE FROM Job")
fun deleteAll()
@Transaction
@Query("SELECT * FROM Job")
fun getAll(): List<JobWrapper>
@Transaction
@Query("SELECT * FROM job WHERE jobid = :jobid")
fun getJobWrapperByJobId(jobid: String ): JobWrapper
}
正如我测试过的,使用的演示/示例如下(显然 JobDao 与上面相同)
使用的 POJO 和实体是/曾经是:-
作业包装器
data class JobWrapper(
@Embedded val job: Job,
@Relation(
parentColumn = "jobid",
entityColumn = "parentId",
entity = Location::class
) var locations : List<Location>
)
工作
@Entity
data class Job (
@PrimaryKey
@NonNull
var jobid : String,
@NonNull
@ColumnInfo(name = "job_status")
var status : String,
@NonNull
var creator : String,
var note : String?,
@NonNull
var organisationId : String,
@NonNull
var type : String,
@NonNull
@ColumnInfo(name = "working_at_customer_id")
var workingAtCustomerId : String,
@NonNull
@ColumnInfo(name = "working_to_customer_id")
var workingToCustomerId : String,
)
位置
@Entity(
foreignKeys = [
ForeignKey(
entity = Job::class,
parentColumns = ["jobid"],
childColumns = ["parentId"],
onUpdate = ForeignKey.CASCADE,
onDelete = ForeignKey.CASCADE
)
])
data class Location (
@PrimaryKey(autoGenerate = true)
var entityId: Long,
@NonNull
var parentId: String,
@NonNull
var locationId: String,
@NonNull
var type: String
) {
constructor() : this(0, "", "", "")
}
@Database 使用了 JobDatabase
@Database(entities = [Location::class,Job::class],version = 1)
abstract class JobDatabase: RoomDatabase() {
abstract fun getJobDao(): JobDAO
companion object {
var instance: JobDatabase? = null
fun getInstance(context: Context): JobDatabase {
if (instance == null) {
instance = Room.databaseBuilder(context, JobDatabase::class.java, "job.db")
.allowMainThreadQueries()
.build()
}
return instance as JobDatabase
}
}
}
测试/演示 Activity MainActivity
class MainActivity : AppCompatActivity() {
lateinit var db: JobDatabase
lateinit var dao: JobDAO
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = JobDatabase.getInstance(this)
dao = db.getJobDao()
var jobId: String = "Job1"
var jw = JobWrapper(
Job(
jobId,
"x",
"Fred",
"Note for Job1",
"Org1",
"A","Cust1",
"Cust1"),
listOf(
Location(0,jobId,"loc1","J"),
Location(0,jobId,"Loc2","K"),
Location(0,jobId,"Loc3","L")
)
)
dao.insert(jw)
dao.insertAll(createJobWrapperList(10))
dao.delete(dao.getJobWrapperByJobId("job6"),true)
var jobWrapper = dao.getJobWrapperByJobId("job7")
jobWrapper.job.creator = "update creator"
for (l in jobWrapper.locations) {
if (l.type == "M") l.type= "UPDATED"
}
dao.update(jobWrapper)
}
fun createJobWrapperList(numberToCreate: Int): List<JobWrapper> {
val l = mutableListOf<JobWrapper>()
for(i in 1..numberToCreate) {
var jid = "job$i"
l.add(
JobWrapper(
Job(jid,"X","Creator$i","Note for $jid","org$jid","T","custA","custT"),
arrayListOf(
Location(0,jid,"loc_$jid.1","L"),
Location(0,jid,"loc_$jid.2","M"),
Location(0,jid,"loc_$jid.3","N")
)
)
)
}
return l.toList()
}
}
这个:-
createJobWrapperList
函数生成的 JobWrappers 列表添加 x (10) 个工作和每个工作的 3 个位置。4.删除通过 getJobWrapperByJobId
获取的 JobWrapper,包括使用 delete
删除底层位置 (true
) 与 jobid“job6”关联的 JobWrapper .update (JobWrapper)
应用更新。警告
使用 JobWrapper 插入,因为它具有 REPLACE 冲突策略,如果它替换,将导致额外的位置,因为将始终生成 entityId。
结果
运行上面的结果:-
工作表:-
位置表:-
你问:-
How do I ensure the relationship to the right parent (job) when inserting the childs (locations)?
我认为以上说明了方法。
关于android - 关系房间数据库 : The class must be either entity or database view,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67843988/
我是一名优秀的程序员,十分优秀!