如何在 Android 中填充中间 table
how to populate intermediate table in Android
我有两个具有多对多关系的 table。所以我创建了一个中间 table,但我找不到正确填充此 table 的方法,因为我无法根据我的数据设置正确的列表。
我有一个 'courses' 列表:每个 'course' 可以有一个或多个类别。
所以我的 table 看起来像这样:
|idcourses|title|date|categories|
|----|----|----|----|
|700|title1|01012021|[54]|
|701|title2|01022021|[54]|
|702|title3|01032021|[48]|
|868|title4|01042021|[47, 52, 54]|
如果我尝试这样的地图:
val myMap = coursesList.map { itcategory to it.idcourses}.distinct()
我有这样的结果:
([54], 700), ([54], 701), ([48], 702), ([47, 52, 54], 868)
整个“[47, 52, 54]”被视为一个字符串,但我希望将其拆分,这样我就可以得到这个:
([54], 700), ([54], 701), ([48], 702), ([47], 868), ([52], 868), ([54], 868)
有人知道如何实现吗??
val tempMap = mutableMapOf<Int, Int>()
for (course in courseList) {
course.categories.map {
tempMap[it] = course.id
}
}
或
val tempMap = mutableMapOf<List<Int>, Int>()
for (value in courseList) {
value.categories.map {
tempMap[listOf(it)] = value.id
}
}
它不是优化的解决方案,但它的工作
我认为您可能尝试以错误的方式执行此操作,因为看起来您的中间 table 有一列您期望类别 ID 列表。
列不能是 list/array 它必须是单个对象。
但是 而不是试图解决这个问题,通常用于中间 table 的是一个 table,它主要有一行映射。即构成映射的两列。其中两列是复合主键。
可以使用具有映射特定数据的其他列。
在你的情况下,一栏 map/reference/relate/associate 到课程,第二栏映射课程。
例如,假设您有课程 Table 和类别 Table 每个:-
@Entity
data class Course(
@PrimaryKey
val idcourses: Long? = null,
val title: String,
val date: String
)
和
@Entity
data class Category(
@PrimaryKey
val idcategories: Long? = null,
val name: String
)
那么你可以将中间 table 作为 :-
@Entity(primaryKeys = ["idcoursesmap","idcategoriesmap"])
data class CourseCategoryMap(
val idcoursesmap: Long,
@ColumnInfo(index = true)
val idcategoriesmap: Long
)
- idcategoriesmap 上的索引可能会提高效率。房间也会发出警告。
- 您可能希望考虑定义外键约束以强制执行参照完整性。 None 为简洁起见已包括在内。
这对于多对多关系已经足够了。
您可能想要检索带有类别的课程,因此您可能需要一个 POJO,例如:-
data class CourseWithCategories(
@Embedded
val course: Course,
@Relation(
entity = Category::class,
parentColumn = "idcourses",
entityColumn = "idcategories",
associateBy = Junction(
value = CourseCategoryMap::class,
parentColumn = "idcoursesmap",
entityColumn = "idcategoriesmap"
)
)
val categories: List<Category>
)
这里有一些可能或可能是的道 wanted/useful:-
abstract class AllDao {
@Insert(onConflict = IGNORE) // Insert single Category
abstract fun insert(category: Category): Long
@Insert(onConflict = IGNORE) // Insert Single Course
abstract fun insert(course: Course): Long
@Insert(onConflict = IGNORE) // Insert Single CourseCategoryMap
abstract fun insert(courseCategoryMap: CourseCategoryMap): Long
/* Inserts many course category maps */
@Insert(onConflict = IGNORE)
abstract fun insert(courseCategoryMaps: List<CourseCategoryMap>): List<Long>
@Query("SELECT * FROM course WHERE course.title=:courseTitle")
abstract fun getCourseByTitle(courseTitle: String): Course
@Query("SELECT * FROM category WHERE category.name LIKE :categoryMask")
abstract fun getCategoriesByNameMask(categoryMask: String): List<Category>
/* For retrieving courses with all the courses categories */
@Transaction
@Query("SELECT * FROM course")
abstract fun getAllCoursesWithCategories(): List<CourseWithCategories>
@Transaction
@Query("")
fun insertManyCataegoriesForACourseByIds(idcourse: Long,categories: List<Long>) {
for (categoryId: Long in categories) {
insert(CourseCategoryMap(idcourse,categoryId))
}
}
// Anoher possibility
@Transaction
@Query("")
fun insertManyCategoriesForACourse(course: Course, categories: List<Category>) {
val categoryIds = ArrayList<Long>()
for (c: Category in categories) {
categoryIds.add(c.idcategories!!)
}
insertManyCataegoriesForACourseByIds(course.idcourses!!,categoryIds)
}
}
演示
为了演示上面的内容,一个非常标准的 class 用 @Database 注释:-
const val DATABASE_NAME = "the_database.db"
const val DATABASE_VERSION =1
@Database(entities = [Course::class,Category::class,CourseCategoryMap::class], exportSchema = false, version = DATABASE_VERSION)
abstract class TheDatabase: RoomDatabase() {
abstract fun getAllDao(): AllDao
companion object {
@Volatile
private var instance: TheDatabase? = null
fun getInstance(context: Context): TheDatabase {
if (instance == null) {
instance = Room.databaseBuilder(context,TheDatabase::class.java, DATABASE_NAME)
.allowMainThreadQueries()
.build()
}
return instance as TheDatabase
}
}
}
和 activity 代码来复制你正在尝试的样子(但两次显示 2 种映射方式,第二次使用比第一种大 20 的类别 ID):-
lateinit var db: TheDatabase
lateinit var dao: AllDao
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = TheDatabase.getInstance(this)
dao = db.getAllDao()
dao.insert(Course(idcourses = 700,title = "title1", date = "01012021"))
dao.insert(Course(701,"title2","01022021"))
dao.insert(Course(702,"title3","01032021"))
dao.insert(Course(868,"title4","01042021"))
// add quite a few categories for demo
for(i in 30..300) {
dao.insert(Category(i.toLong(),"Category${i}"))
}
//example of what you are trying to do (first)
var currentCourse = dao.getCourseByTitle("title1")
dao.insertManyCataegoriesForACourseByIds(currentCourse.idcourses!!, listOf(54))
dao.insertManyCataegoriesForACourseByIds(dao.getCourseByTitle("title2").idcourses!!, listOf(54))
dao.insertManyCataegoriesForACourseByIds(dao.getCourseByTitle("title3").idcourses!!, listOf(48))
dao.insertManyCataegoriesForACourseByIds(dao.getCourseByTitle("title4").idcourses!!, listOf(47,52,54))
// second (does the same but uses categroyids 20 greater than the first)
val coursecategorymaplist = listOf<CourseCategoryMap>(
CourseCategoryMap(700,74),
CourseCategoryMap(701,74),
CourseCategoryMap(702,68),
CourseCategoryMap(868,67),
CourseCategoryMap(868,72),
CourseCategoryMap(868,74)
)
dao.insert(coursecategorymaplist)
// Extract results
for (cwc: CourseWithCategories in dao.getAllCoursesWithCategories()) {
Log.d("DBINFO","Course is ${cwc.course.title}, date is ${cwc.course.date} it has ${cwc.categories.size} categories they are:-")
for (c: Category in cwc.categories) {
Log.d("DBINFO","\tCategory is ${c.name}")
}
}
}
结果
日志包括(注意类别数量的两倍):-
D/DBINFO: Course is title1, date is 01012021 it has 2 categories they are:-
D/DBINFO: Category is Category54
D/DBINFO: Category is Category74
D/DBINFO: Course is title2, date is 01022021 it has 2 categories they are:-
D/DBINFO: Category is Category54
D/DBINFO: Category is Category74
D/DBINFO: Course is title3, date is 01032021 it has 2 categories they are:-
D/DBINFO: Category is Category48
D/DBINFO: Category is Category68
D/DBINFO: Course is title4, date is 01042021 it has 6 categories they are:-
D/DBINFO: Category is Category47
D/DBINFO: Category is Category52
D/DBINFO: Category is Category54
D/DBINFO: Category is Category67
D/DBINFO: Category is Category72
D/DBINFO: Category is Category74
数据库
课程Table:-
类别Table(部分)
CourseCategoryMap(中级table)
我有两个具有多对多关系的 table。所以我创建了一个中间 table,但我找不到正确填充此 table 的方法,因为我无法根据我的数据设置正确的列表。
我有一个 'courses' 列表:每个 'course' 可以有一个或多个类别。 所以我的 table 看起来像这样:
|idcourses|title|date|categories|
|----|----|----|----|
|700|title1|01012021|[54]|
|701|title2|01022021|[54]|
|702|title3|01032021|[48]|
|868|title4|01042021|[47, 52, 54]|
如果我尝试这样的地图:
val myMap = coursesList.map { itcategory to it.idcourses}.distinct()
我有这样的结果:
([54], 700), ([54], 701), ([48], 702), ([47, 52, 54], 868)
整个“[47, 52, 54]”被视为一个字符串,但我希望将其拆分,这样我就可以得到这个:
([54], 700), ([54], 701), ([48], 702), ([47], 868), ([52], 868), ([54], 868)
有人知道如何实现吗??
val tempMap = mutableMapOf<Int, Int>()
for (course in courseList) {
course.categories.map {
tempMap[it] = course.id
}
}
或
val tempMap = mutableMapOf<List<Int>, Int>()
for (value in courseList) {
value.categories.map {
tempMap[listOf(it)] = value.id
}
}
它不是优化的解决方案,但它的工作
我认为您可能尝试以错误的方式执行此操作,因为看起来您的中间 table 有一列您期望类别 ID 列表。
列不能是 list/array 它必须是单个对象。
但是 而不是试图解决这个问题,通常用于中间 table 的是一个 table,它主要有一行映射。即构成映射的两列。其中两列是复合主键。
可以使用具有映射特定数据的其他列。
在你的情况下,一栏 map/reference/relate/associate 到课程,第二栏映射课程。
例如,假设您有课程 Table 和类别 Table 每个:-
@Entity
data class Course(
@PrimaryKey
val idcourses: Long? = null,
val title: String,
val date: String
)
和
@Entity
data class Category(
@PrimaryKey
val idcategories: Long? = null,
val name: String
)
那么你可以将中间 table 作为 :-
@Entity(primaryKeys = ["idcoursesmap","idcategoriesmap"])
data class CourseCategoryMap(
val idcoursesmap: Long,
@ColumnInfo(index = true)
val idcategoriesmap: Long
)
- idcategoriesmap 上的索引可能会提高效率。房间也会发出警告。
- 您可能希望考虑定义外键约束以强制执行参照完整性。 None 为简洁起见已包括在内。
这对于多对多关系已经足够了。
您可能想要检索带有类别的课程,因此您可能需要一个 POJO,例如:-
data class CourseWithCategories(
@Embedded
val course: Course,
@Relation(
entity = Category::class,
parentColumn = "idcourses",
entityColumn = "idcategories",
associateBy = Junction(
value = CourseCategoryMap::class,
parentColumn = "idcoursesmap",
entityColumn = "idcategoriesmap"
)
)
val categories: List<Category>
)
这里有一些可能或可能是的道 wanted/useful:-
abstract class AllDao {
@Insert(onConflict = IGNORE) // Insert single Category
abstract fun insert(category: Category): Long
@Insert(onConflict = IGNORE) // Insert Single Course
abstract fun insert(course: Course): Long
@Insert(onConflict = IGNORE) // Insert Single CourseCategoryMap
abstract fun insert(courseCategoryMap: CourseCategoryMap): Long
/* Inserts many course category maps */
@Insert(onConflict = IGNORE)
abstract fun insert(courseCategoryMaps: List<CourseCategoryMap>): List<Long>
@Query("SELECT * FROM course WHERE course.title=:courseTitle")
abstract fun getCourseByTitle(courseTitle: String): Course
@Query("SELECT * FROM category WHERE category.name LIKE :categoryMask")
abstract fun getCategoriesByNameMask(categoryMask: String): List<Category>
/* For retrieving courses with all the courses categories */
@Transaction
@Query("SELECT * FROM course")
abstract fun getAllCoursesWithCategories(): List<CourseWithCategories>
@Transaction
@Query("")
fun insertManyCataegoriesForACourseByIds(idcourse: Long,categories: List<Long>) {
for (categoryId: Long in categories) {
insert(CourseCategoryMap(idcourse,categoryId))
}
}
// Anoher possibility
@Transaction
@Query("")
fun insertManyCategoriesForACourse(course: Course, categories: List<Category>) {
val categoryIds = ArrayList<Long>()
for (c: Category in categories) {
categoryIds.add(c.idcategories!!)
}
insertManyCataegoriesForACourseByIds(course.idcourses!!,categoryIds)
}
}
演示
为了演示上面的内容,一个非常标准的 class 用 @Database 注释:-
const val DATABASE_NAME = "the_database.db"
const val DATABASE_VERSION =1
@Database(entities = [Course::class,Category::class,CourseCategoryMap::class], exportSchema = false, version = DATABASE_VERSION)
abstract class TheDatabase: RoomDatabase() {
abstract fun getAllDao(): AllDao
companion object {
@Volatile
private var instance: TheDatabase? = null
fun getInstance(context: Context): TheDatabase {
if (instance == null) {
instance = Room.databaseBuilder(context,TheDatabase::class.java, DATABASE_NAME)
.allowMainThreadQueries()
.build()
}
return instance as TheDatabase
}
}
}
和 activity 代码来复制你正在尝试的样子(但两次显示 2 种映射方式,第二次使用比第一种大 20 的类别 ID):-
lateinit var db: TheDatabase
lateinit var dao: AllDao
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = TheDatabase.getInstance(this)
dao = db.getAllDao()
dao.insert(Course(idcourses = 700,title = "title1", date = "01012021"))
dao.insert(Course(701,"title2","01022021"))
dao.insert(Course(702,"title3","01032021"))
dao.insert(Course(868,"title4","01042021"))
// add quite a few categories for demo
for(i in 30..300) {
dao.insert(Category(i.toLong(),"Category${i}"))
}
//example of what you are trying to do (first)
var currentCourse = dao.getCourseByTitle("title1")
dao.insertManyCataegoriesForACourseByIds(currentCourse.idcourses!!, listOf(54))
dao.insertManyCataegoriesForACourseByIds(dao.getCourseByTitle("title2").idcourses!!, listOf(54))
dao.insertManyCataegoriesForACourseByIds(dao.getCourseByTitle("title3").idcourses!!, listOf(48))
dao.insertManyCataegoriesForACourseByIds(dao.getCourseByTitle("title4").idcourses!!, listOf(47,52,54))
// second (does the same but uses categroyids 20 greater than the first)
val coursecategorymaplist = listOf<CourseCategoryMap>(
CourseCategoryMap(700,74),
CourseCategoryMap(701,74),
CourseCategoryMap(702,68),
CourseCategoryMap(868,67),
CourseCategoryMap(868,72),
CourseCategoryMap(868,74)
)
dao.insert(coursecategorymaplist)
// Extract results
for (cwc: CourseWithCategories in dao.getAllCoursesWithCategories()) {
Log.d("DBINFO","Course is ${cwc.course.title}, date is ${cwc.course.date} it has ${cwc.categories.size} categories they are:-")
for (c: Category in cwc.categories) {
Log.d("DBINFO","\tCategory is ${c.name}")
}
}
}
结果
日志包括(注意类别数量的两倍):-
D/DBINFO: Course is title1, date is 01012021 it has 2 categories they are:-
D/DBINFO: Category is Category54
D/DBINFO: Category is Category74
D/DBINFO: Course is title2, date is 01022021 it has 2 categories they are:-
D/DBINFO: Category is Category54
D/DBINFO: Category is Category74
D/DBINFO: Course is title3, date is 01032021 it has 2 categories they are:-
D/DBINFO: Category is Category48
D/DBINFO: Category is Category68
D/DBINFO: Course is title4, date is 01042021 it has 6 categories they are:-
D/DBINFO: Category is Category47
D/DBINFO: Category is Category52
D/DBINFO: Category is Category54
D/DBINFO: Category is Category67
D/DBINFO: Category is Category72
D/DBINFO: Category is Category74
数据库
课程Table:-
类别Table(部分)
CourseCategoryMap(中级table)