我有一个将 Workers 连接到 Job 的数据库。 每个工作都由海报组成,每个海报只能分配给一个人。
一切都很简单,但流程有点复杂。 工人需要先申请某个职位,然后才能将其分配给他们。 受聘后,工人可以开始选择他们想要制作的海报。
如果有一种方法可以向我的连接表添加附加信息,那就太好了。 这样,在我的 Jobs 和 Workers Junction 表中,我可以执行 2 个单独的查询,一个查询已应用作业,另一个查询已批准作业。
另一种方法是有一个单独的连接表,一个用于已申请的工作,另一个用于已接受的工作;但这会变得非常混乱和烦人,因为我必须处理两个单独的列表。 最好的是,如果我可以在连接表中添加一列,然后在作业列表中使用该列,并且单个作业可以直接申请或批准。
这是有问题的实体和关系
@Entity(
foreignKeys = [
ForeignKey(
entity = Owner::class,
parentColumns = ["owner_id"],
childColumns = ["owner_id_map"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
)
]
)
data class Job (
@PrimaryKey val job_id: Long,
val status: Int,
@ColumnInfo(index = true)
val owner_id_map: Long,
val title: String,
val city: String
) : Serializable
JobPW 代表“工作与工人和海报”
data class JobPW(
@Embedded val job: Job,
@Relation(
parentColumn = "job_id",
entityColumn = "worker_id",
associateBy = Junction(JobWorkerCrossRef::class)
)
val workers: List<Worker>,
@Relation(
entity = Poster::class,
parentColumn = "job_id",
entityColumn = "job_id_map"
)
val posters: List<PosterWithWorker>
) : Serializable
@Entity
class Worker(
@PrimaryKey
@ColumnInfo(name = "worker_id")
val worker_id: Long,
val workerName: String,
) : Serializabe
@Entity(
primaryKeys = ["job_id","worker_id"], /* composite primary key */
foreignKeys = [
ForeignKey(
entity = Job::class,
parentColumns = ["job_id"],
childColumns = ["job_id"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
),
ForeignKey(
entity = Worker::class,
parentColumns = ["worker_id"],
childColumns = ["worker_id"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
)
]
)
data class JobWorkerCrossRef(
val job_id: Long,
@ColumnInfo(index = true)
val worker_id: Long,
)
这是构建职位列表的查询。
@Transaction
@Query("SELECT * FROM job")
fun getJobsFlow(): Flow<List<JobPW>>
@Transaction
@Query("SELECT * FROM job")
suspend fun getJobs(): List<JobPW>
(一个版本就是一个流程,我想最好用这个)
如果有一种方法可以向我的连接表添加附加信息,那就太好了。
有一个办法。您只需(取决于结果)将该表视为普通表并从中检索数据。
所以你可以有这样的东西:-
data class JobPW(
@Embedded val job: Job,
@Relation(
parentColumn = "job_id",
entityColumn = "worker_id",
associateBy = Junction(JobWorkerCrossRef::class)
)
/*<<<<<<<<<< ADDDED >>>>>>>>>>*/
val workers: List<Worker> ,
@Relation(
entity = JobWorkerCrossRef::class,
entityColumn = "job_id",
parentColumn = "job_id"
)
val junctionWithExtra: List<JobWorkerCrossRef>,
(<<<<<<<<<< END OF ADDITION >>>>>>>>>*/
@Relation(
entity = Poster::class,
parentColumn = "job_id",
entityColumn = "job_id_map"
)
val posters: List<PosterWithWorker>
) : Serializable
工作示例
以下是基于问题代码的工作示例,添加了省略的类来应对(为了演示的简洁性,适合在主线程上运行,没有流程/暂停)。所以演示的整个数据库代码是:-
@Entity
data class Owner(
@PrimaryKey
val owner_id: Long?=null,
val ownerName: String
)
@Entity
data class Poster(
@PrimaryKey
val poster_id: Long?=null,
@ColumnInfo(index = true)
val job_id_map: Long,
val worker_id: Long,
val posterName: String
)
@Entity(
foreignKeys = [
ForeignKey(
entity = Owner::class,
parentColumns = ["owner_id"],
childColumns = ["owner_id_map"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
)
]
)
data class Job (
@PrimaryKey val job_id: Long?=null,
val status: Int,
@ColumnInfo(index = true)
val owner_id_map: Long,
val title: String,
val city: String
) : Serializable
data class JobPW(
@Embedded val job: Job,
@Relation(
parentColumn = "job_id",
entityColumn = "worker_id",
associateBy = Junction(JobWorkerCrossRef::class)
)
val workers: List<Worker> ,
@Relation(
entity = JobWorkerCrossRef::class,
entityColumn = "job_id",
parentColumn = "job_id"
)
val junctionWithExtra: List<JobWorkerCrossRef>,
@Relation(
entity = Poster::class,
parentColumn = "job_id",
entityColumn = "job_id_map"
)
val posters: List<PosterWithWorker>
) : Serializable
@Entity
data class Worker(
@PrimaryKey
@ColumnInfo(name = "worker_id")
val worker_id: Long?=null,
val workerName: String
) : Serializable
data class PosterWithWorker(
@Embedded
val poster: Poster,
@Relation(
entity = Worker::class,
entityColumn = "worker_id",
parentColumn = "poster_id"
)
val workers: List<Worker>
)
@Entity(
primaryKeys = ["job_id","worker_id"], /* composite primary key */
foreignKeys = [
ForeignKey(
entity = Job::class,
parentColumns = ["job_id"],
childColumns = ["job_id"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
),
ForeignKey(
entity = Worker::class,
parentColumns = ["worker_id"],
childColumns = ["worker_id"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
)
]
)
data class JobWorkerCrossRef(
val job_id: Long,
@ColumnInfo(index = true)
val worker_id: Long,
val extraData: String
)
@Dao
interface AllDAOs {
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(owner: Owner): Long
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(worker: Worker): Long
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(poster: Poster): Long
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(job: Job): Long
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(jobWorkerCrossRef: JobWorkerCrossRef): Long
@Transaction
@Query("SELECT * FROM job")
/*suspend*/ fun getJobs(): List<JobPW>
}
@Database(entities = [Owner::class,Job::class,Poster::class,Worker::class,JobWorkerCrossRef::class], exportSchema = false, version = 1)
abstract class TheDatabase: RoomDatabase() {
abstract fun getAllDAOs(): AllDAOs
companion object {
private var instance: TheDatabase?=null
fun getInstance(context: Context): TheDatabase {
if (instance==null) {
instance=Room.databaseBuilder(context,TheDatabase::class.java,"the_database.db")
.allowMainThreadQueries()
.build()
}
return instance as TheDatabase
}
}
}
为了演示在活动中使用以下代码。该代码加载一些数据(仅用于单次运行,而不是重复),然后使用修改后的 JobPW POJO 使用问题中的查询提取数据(请注意,修改它只是为了获取额外的数据):-
class MainActivity : AppCompatActivity() {
lateinit var db: TheDatabase
lateinit var dao: AllDAOs
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = TheDatabase.getInstance(this)
dao = db.getAllDAOs()
val o1id = dao.insert(Owner(ownerName = "Owner1"))
val o2id = dao.insert(Owner(ownerName = "Owner2"))
val o3id = dao.insert(Owner(ownerName = "Owner3"))
val j1id = dao.insert(Job(status = 1, owner_id_map = o1id, title = "Job1", city = "Somewhere"))
val j2id = dao.insert(Job(status = 2, owner_id_map = o1id, title = "Job2", city = "Elsewhere"))
val j3id = dao.insert(Job(status = 3, owner_id_map = o2id, title = "Job3", city = "Everywhere"))
val j4id = dao.insert(Job(status = 4, owner_id_map = o3id, title = "Job4", city = "Nowhere"))
val w1id = dao.insert(Worker(workerName = "Fred"))
val w2id = dao.insert(Worker(workerName = "Mary"))
val w3id = dao.insert(Worker(workerName = "Jane"))
val w4id = dao.insert(Worker(workerName = "Tom"))
val w5id = dao.insert(Worker(workerName = "Anne"))
val w6id = dao.insert(Worker(workerName = "Bill"))
val p1id = dao.insert(Poster(job_id_map = j1id, worker_id = w6id, posterName = "Poster1 for Job1 by Bill"))
val p2id = dao.insert(Poster(job_id_map = j1id, worker_id = w5id, posterName = "Poster2 for Job1 by Anne"))
val p3Id = dao.insert(Poster(job_id_map = j2id, worker_id = w6id, posterName = "Poster3 for Job2 by Bill"))
val p4id = dao.insert(Poster(job_id_map = j3id, worker_id = w4id, posterName = "Poster4 for Job3 by Tom"))
dao.insert(JobWorkerCrossRef(job_id = j1id, worker_id = w1id, extraData = "J1W1ABC"))
dao.insert(JobWorkerCrossRef(job_id = j1id, worker_id = w3id, extraData = "J1W3DEF"))
dao.insert(JobWorkerCrossRef(j1id,w5id,"J1W5GHI"))
dao.insert(JobWorkerCrossRef(j2id,w2id,"J2W2JKL"))
dao.insert(JobWorkerCrossRef(j2id ,w4id,"J2W4MNO"))
dao.insert(JobWorkerCrossRef(j2id,w6id,"J2W6PQR"))
dao.insert(JobWorkerCrossRef(j4id,w1id,"J4W1STU"))
dao.insert(JobWorkerCrossRef(j4id,w2id,"J4W2VWX"))
dao.insert(JobWorkerCrossRef(j4id,w3id,"J4W3YZ1"))
dao.insert(JobWorkerCrossRef(j4id,w4id,"J4W4234"))
dao.insert(JobWorkerCrossRef(j4id,w5id,"J4W5567"))
dao.insert(JobWorkerCrossRef(j4id,w6id,"J4W6890"))
for(jpw in dao.getJobs()) {
val pli = StringBuilder()
for (p in jpw.posters) {
val pwli = StringBuilder()
for (w in p.workers) {
pwli.append("\n\n\tWorker is ${w.workerName} ID is ${w.worker_id} (via Poster)")
}
pli.append("\n\tPoster is ${p.poster.posterName} ID is ${p.poster.poster_id} mapped to JobID ${p.poster.job_id_map} there are ${p.workers.size} Workers. They are:-${pwli}")
}
val jpel = StringBuilder()
for (je in jpw.junctionWithExtra) {
jpel.append("\n\tJunctionWithExtra (Extra Data) is ${je.extraData} JobID is ${je.job_id} WorkerID is ${je.worker_id}")
}
val jwl = StringBuilder()
for (w in jpw.workers) {
jwl.append(("\n\tWorker is ${w.workerName} ID is ${w.worker_id} (via Job)"))
}
Log.d(
"DBINFO",
"Job is ${jpw.job.title} City is ${jpw.job.city} Status is ${jpw.job.status} JOBID is ${jpw.job.job_id} OwenerID is ${jpw.job.owner_id_map}" +
".\nThere are ${jpw.posters}! They are:-$pli" +
".\nThere are ${jpw.junctionWithExtra.size} Junctions With Extra Data! They are:-${jpel}" +
".\nThere are ${jpw.workers.size} Workers!. They are:-${jwl}")
}
}
}
结果
2023-03-29 11:20:35.042 D/DBINFO: Job is Job1 City is Somewhere Status is 1 JOBID is 1 OwenerID is 1.
There are [PosterWithWorker(poster=Poster(poster_id=1, job_id_map=1, worker_id=6, posterName=Poster1 for Job1 by Bill), workers=[Worker(worker_id=1, workerName=Fred)]), PosterWithWorker(poster=Poster(poster_id=2, job_id_map=1, worker_id=5, posterName=Poster2 for Job1 by Anne), workers=[Worker(worker_id=2, workerName=Mary)])]! They are:-
Poster is Poster1 for Job1 by Bill ID is 1 mapped to JobID 1 there are 1 Workers. They are:-
Worker is Fred ID is 1 (via Poster)
Poster is Poster2 for Job1 by Anne ID is 2 mapped to JobID 1 there are 1 Workers. They are:-
Worker is Mary ID is 2 (via Poster).
There are 3 Junctions With Extra Data! They are:-
JunctionWithExtra (Extra Data) is J1W1ABC JobID is 1 WorkerID is 1
JunctionWithExtra (Extra Data) is J1W3DEF JobID is 1 WorkerID is 3
JunctionWithExtra (Extra Data) is J1W5GHI JobID is 1 WorkerID is 5.
There are 3 Workers!. They are:-
Worker is Fred ID is 1 (via Job)
Worker is Jane ID is 3 (via Job)
Worker is Anne ID is 5 (via Job)
2023-03-29 11:20:35.042 D/DBINFO: Job is Job2 City is Elsewhere Status is 2 JOBID is 2 OwenerID is 1.
There are [PosterWithWorker(poster=Poster(poster_id=3, job_id_map=2, worker_id=6, posterName=Poster3 for Job2 by Bill), workers=[Worker(worker_id=3, workerName=Jane)])]! They are:-
Poster is Poster3 for Job2 by Bill ID is 3 mapped to JobID 2 there are 1 Workers. They are:-
Worker is Jane ID is 3 (via Poster).
There are 3 Junctions With Extra Data! They are:-
JunctionWithExtra (Extra Data) is J2W2JKL JobID is 2 WorkerID is 2
JunctionWithExtra (Extra Data) is J2W4MNO JobID is 2 WorkerID is 4
JunctionWithExtra (Extra Data) is J2W6PQR JobID is 2 WorkerID is 6.
There are 3 Workers!. They are:-
Worker is Mary ID is 2 (via Job)
Worker is Tom ID is 4 (via Job)
Worker is Bill ID is 6 (via Job)
2023-03-29 11:20:35.042 D/DBINFO: Job is Job3 City is Everywhere Status is 3 JOBID is 3 OwenerID is 2.
There are [PosterWithWorker(poster=Poster(poster_id=4, job_id_map=3, worker_id=4, posterName=Poster4 for Job3 by Tom), workers=[Worker(worker_id=4, workerName=Tom)])]! They are:-
Poster is Poster4 for Job3 by Tom ID is 4 mapped to JobID 3 there are 1 Workers. They are:-
Worker is Tom ID is 4 (via Poster).
There are 0 Junctions With Extra Data! They are:-.
There are 0 Workers!. They are:-
2023-03-29 11:20:35.047 D/DBINFO: Job is Job4 City is Nowhere Status is 4 JOBID is 4 OwenerID is 3.
There are []! They are:-.
There are 6 Junctions With Extra Data! They are:-
JunctionWithExtra (Extra Data) is J4W1STU JobID is 4 WorkerID is 1
JunctionWithExtra (Extra Data) is J4W2VWX JobID is 4 WorkerID is 2
JunctionWithExtra (Extra Data) is J4W3YZ1 JobID is 4 WorkerID is 3
JunctionWithExtra (Extra Data) is J4W4234 JobID is 4 WorkerID is 4
JunctionWithExtra (Extra Data) is J4W5567 JobID is 4 WorkerID is 5
JunctionWithExtra (Extra Data) is J4W6890 JobID is 4 WorkerID is 6.
There are 6 Workers!. They are:-
Worker is Fred ID is 1 (via Job)
Worker is Mary ID is 2 (via Job)
Worker is Jane ID is 3 (via Job)
Worker is Tom ID is 4 (via Job)
Worker is Anne ID is 5 (via Job)
Worker is Bill ID is 6 (via Job)
可以通过
@Relation
将 JobWorkerCrossRef 表视为普通表而不是连接表来检索相应的额外数据。
因此,简而言之,为了不从联结表获取数据,您可以通过联结将其用作联结表。
更进一步,将 Worker 和 Extra 数据结合起来
要获取映射 Worker 和 Extra 的组合数据,您可以使用 POJO,通过
@Relation
ing Worker 来获取特定 Worker 详细信息。
作为后者的示例,您可以:-
data class JobPWE(
@Embedded
val job: Job,
@Relation(
entity = JobWorkerCrossRef::class,
parentColumn = "job_id",
entityColumn = "job_id"
)
val junctionWithExtra: List<JobWorkerCrossRefWithWorker>,
@Relation(
entity = Poster::class,
parentColumn = "job_id",
entityColumn = "job_id_map"
)
val posters: List<PosterWithWorker>
)
例如
data class JobWorkerCrossRefWithWorker(
@Embedded
val jwxr: JobWorkerCrossRef,
@Relation(
entity = Worker::class,
parentColumn = "worker_id",
entityColumn = "worker_id"
)
val workerDetail: Worker
)
连同(允许getJobs保持原样):-
@Transaction
@Query("SELECT * FROM job")
fun getJobsV2(): List<JobPWE>
然后在活动代码中使用以下内容:-
for (jpwe in dao.getJobsV2()) {
val pli = StringBuilder()
for (p in jpwe.posters) {
val pwli = StringBuilder()
for (w in p.workers) {
pwli.append("\n\t\tWorker is ${w.workerName} ID is ${w.worker_id} (via Poster)")
}
pli.append("\n\tPoster is ${p.poster.posterName} ID is ${p.poster.poster_id} mapped to JobID ${p.poster.job_id_map} there are ${p.workers.size} Workers. They are:-${pwli}")
}
val jpel = StringBuilder()
for (je in jpwe.junctionWithExtra) {
jpel.append(
"\n\tJunctionWithExtra (Extra Data) is ${je.jwxr.extraData} (from junction) " +
"JobID is ${je.jwxr.job_id} (from junction table) " +
"WorkerID is ${je.jwxr} (from junction table) " +
"WorkerName is ${je.workerDetail.workerName} (from Worker table related to the junction table)"
)
}
Log.d(
"DBINFOV2",
"Job is ${jpwe.job.title} City is ${jpwe.job.city} Status is ${jpwe.job.status} JOBID is ${jpwe.job.job_id} OwnerID is ${jpwe.job.owner_id_map}" +
".\nThere are ${jpwe.posters.size} posters! They are:-$pli" +
".\nThere are ${jpwe.junctionWithExtra.size} Junctions With Extra Data! They are:-${jpel}"
)
}
然后,当使用相同的数据时,日志中的结果将显示:-
2023-03-29 16:44:02.176 D/DBINFOV2: Job is Job1 City is Somewhere Status is 1 JOBID is 1 OwnerID is 1.
There are 2 posters! They are:-
Poster is Poster1 for Job1 by Bill ID is 1 mapped to JobID 1 there are 1 Workers. They are:-
Worker is Fred ID is 1 (via Poster)
Poster is Poster2 for Job1 by Anne ID is 2 mapped to JobID 1 there are 1 Workers. They are:-
Worker is Mary ID is 2 (via Poster).
There are 3 Junctions With Extra Data! They are:-
JunctionWithExtra (Extra Data) is J1W1ABC (from junction) JobID is 1 (from junction table) WorkerID is JobWorkerCrossRef(job_id=1, worker_id=1, extraData=J1W1ABC) (from junction table) WorkerName is Fred (from Worker table related to the junction table)
JunctionWithExtra (Extra Data) is J1W3DEF (from junction) JobID is 1 (from junction table) WorkerID is JobWorkerCrossRef(job_id=1, worker_id=3, extraData=J1W3DEF) (from junction table) WorkerName is Jane (from Worker table related to the junction table)
JunctionWithExtra (Extra Data) is J1W5GHI (from junction) JobID is 1 (from junction table) WorkerID is JobWorkerCrossRef(job_id=1, worker_id=5, extraData=J1W5GHI) (from junction table) WorkerName is Anne (from Worker table related to the junction table)
2023-03-29 16:44:02.176 D/DBINFOV2: Job is Job2 City is Elsewhere Status is 2 JOBID is 2 OwnerID is 1.
There are 1 posters! They are:-
Poster is Poster3 for Job2 by Bill ID is 3 mapped to JobID 2 there are 1 Workers. They are:-
Worker is Jane ID is 3 (via Poster).
There are 3 Junctions With Extra Data! They are:-
JunctionWithExtra (Extra Data) is J2W2JKL (from junction) JobID is 2 (from junction table) WorkerID is JobWorkerCrossRef(job_id=2, worker_id=2, extraData=J2W2JKL) (from junction table) WorkerName is Mary (from Worker table related to the junction table)
JunctionWithExtra (Extra Data) is J2W4MNO (from junction) JobID is 2 (from junction table) WorkerID is JobWorkerCrossRef(job_id=2, worker_id=4, extraData=J2W4MNO) (from junction table) WorkerName is Tom (from Worker table related to the junction table)
JunctionWithExtra (Extra Data) is J2W6PQR (from junction) JobID is 2 (from junction table) WorkerID is JobWorkerCrossRef(job_id=2, worker_id=6, extraData=J2W6PQR) (from junction table) WorkerName is Bill (from Worker table related to the junction table)
2023-03-29 16:44:02.176 D/DBINFOV2: Job is Job3 City is Everywhere Status is 3 JOBID is 3 OwnerID is 2.
There are 1 posters! They are:-
Poster is Poster4 for Job3 by Tom ID is 4 mapped to JobID 3 there are 1 Workers. They are:-
Worker is Tom ID is 4 (via Poster).
There are 0 Junctions With Extra Data! They are:-
2023-03-29 16:44:02.177 D/DBINFOV2: Job is Job4 City is Nowhere Status is 4 JOBID is 4 OwnerID is 3.
There are 0 posters! They are:-.
There are 6 Junctions With Extra Data! They are:-
JunctionWithExtra (Extra Data) is J4W1STU (from junction) JobID is 4 (from junction table) WorkerID is JobWorkerCrossRef(job_id=4, worker_id=1, extraData=J4W1STU) (from junction table) WorkerName is Fred (from Worker table related to the junction table)
JunctionWithExtra (Extra Data) is J4W2VWX (from junction) JobID is 4 (from junction table) WorkerID is JobWorkerCrossRef(job_id=4, worker_id=2, extraData=J4W2VWX) (from junction table) WorkerName is Mary (from Worker table related to the junction table)
JunctionWithExtra (Extra Data) is J4W3YZ1 (from junction) JobID is 4 (from junction table) WorkerID is JobWorkerCrossRef(job_id=4, worker_id=3, extraData=J4W3YZ1) (from junction table) WorkerName is Jane (from Worker table related to the junction table)
JunctionWithExtra (Extra Data) is J4W4234 (from junction) JobID is 4 (from junction table) WorkerID is JobWorkerCrossRef(job_id=4, worker_id=4, extraData=J4W4234) (from junction table) WorkerName is Tom (from Worker table related to the junction table)
JunctionWithExtra (Extra Data) is J4W5567 (from junction) JobID is 4 (from junction table) WorkerID is JobWorkerCrossRef(job_id=4, worker_id=5, extraData=J4W5567) (from junction table) WorkerName is Anne (from Worker table related to the junction table)
JunctionWithExtra (Extra Data) is J4W6890 (from junction) JobID is 4 (from junction table) WorkerID is JobWorkerCrossRef(job_id=4, worker_id=6, extraData=J4W6890) (from junction table) WorkerName is Bill (from Worker table related to the junction table)
即Worker 和 Extra 数据被合并。
(一个版本是一个流程,我想最好使用这个)
封装在 Flow 中与处理 Flow 之外的操作一样简单。