管理多对多关系的典型方法是使用一个中间表来映射关系。这样的表将有两列,每列标识关系的相应行。
例如,假设您有 id 为 1,2,3 .... 等的成员和团队 1000,1001,1002 等(1000+ 使用纯粹是为了便于区分这种解释)。
然后映射表我有如下行: -
1000,1
1000,3
1000,5
1001,2
1001,4
1002,1
1002,2
1002,3
1002,4
1002,5
因此,由 1000 标识的团队具有由 1,3 和 5 标识的成员,由 1001 标识的团队具有由 2 和 3 标识的成员,而 1002 具有由 1 到 5 标识的成员。
要在 Room 中实现这一点,您需要拥有核心实体成员和团队,而不考虑它们之间的关系:-
@Entity
data class Member(
@PrimaryKey
var id: String = "",
var name: String = "",
/** teamsPositionsMap key -> teamId , value -> position */
//private var tPM: Map<String, String> = mapOf(),
)
和
@Entity
data class Team(
@PrimaryKey
var id: String = "",
var name: String = ""
//var memIds: List<String> = listOf(),
/** get it by query memId */
//var memberList: List<Member>? = null,
)
然后你有中间映射表(又名关联表,链接表....): -
@Entity(
primaryKeys = ["memberIdMap","teamIdMap"],
indices = [Index(value = ["teamIdMap"], unique = false)],
foreignKeys = [
ForeignKey(
entity = Member::class,
parentColumns = ["id"],
childColumns = ["memberIdMap"],
onUpdate = ForeignKey.CASCADE,
onDelete = ForeignKey.CASCADE
),
ForeignKey(
entity = Team::class,
parentColumns = ["id"],
childColumns = ["teamIdMap"],
onUpdate = ForeignKey.CASCADE,
onDelete = ForeignKey.CASCADE
)
]
)
data class MemberTeamMap(
var memberIdMap: String,
var teamIdMap: String
)
- 对于 Room,需要 PRIMARY KEY,复合主键已被定义为 PRIMARY KEY 的必要条件是它保存 UNIQUE 值,因此仅将任一列作为主键将不允许多个列。
- 另一列上的索引不是必需的,但如果省略,房间会发出警告。
- 不需要外键,但它们确实强制引用完整性,即映射不包含孤儿。
要真正让成员与他们的团队或与成员的团队,那么您需要一个具有父级(成员或团队)和列表/数组(成员的团队和团队的成员)的 POJO(不是表)。
为方便起见,您使用 Room 注释 @Embedded 为父级和 @Relation 为子级。
所以你可以: -
data class TeamWithMembers(
@Embedded
var team: Team,
@Relation(
entity = Member::class, parentColumn = "id", entityColumn = "id",
associateBy = Junction(
value = MemberTeamMap::class, parentColumn = "teamIdMap", entityColumn = "memberIdMap"
)
)
var members: List<Member>
)
和/或:-
data class MemberWithTeams (
@Embedded
var member: Member,
@Relation(
entity = Team::class, parentColumn = "id", entityColumn = "id",
associateBy = Junction(
MemberTeamMap::class,parentColumn = "memberIdMap", entityColumn = "teamIdMap"
)
)
var teams: List<Team>
)
各自的查询,只需要检索父级,Room 然后提取所有子级。因此,您可以在 a/your Dao/s 中编写以下代码:-
@Insert
abstract fun insert(member: Member): Long
@Insert
abstract fun insert(team: Team): Long
@Insert
abstract fun insert(memberTeamMap: MemberTeamMap): Long
@Query("SELECT * FROM member")
@Transaction
abstract fun getAllMembersWithTeams(): List<MemberWithTeams>
@Query("SELECT * FROM team")
@Transaction
abstract fun getAllTeamsWithMember(): List<TeamWithMembers>
将上述内容付诸实践以进行演示,请考虑以下几点:-
var tag = "TEAMDBINFO"
db = TheDatabase.getInstance(this)
dao = db.getAllDao()
// Add some members and teams
dao.insert(Member(id = "M1",name = "Member1"))
dao.insert(Member(id = "M2", name = "Member2"))
dao.insert(Member(id = "M3", name = "Member3"))
dao.insert(Member(id = "M4", name = "Member4"))
dao.insert(Member(id = "M5", name = "Member5"))
dao.insert(Team(id = "T1", name = "Team1"))
dao.insert(Team(id = "T2", name = "Team2"))
dao.insert(Team(id = "T3",name = "Team3"))
dao.insert(Team(id = "T4",name = "Team4"))
// do the mapping
dao.insert(MemberTeamMap("M1","T1"))
dao.insert(MemberTeamMap("M3","T1"))
dao.insert(MemberTeamMap("M5","T1"))
dao.insert(MemberTeamMap("M2","T2"))
dao.insert(MemberTeamMap("M4","T2"))
dao.insert(MemberTeamMap("M1","T3"))
dao.insert(MemberTeamMap("M2","T3"))
dao.insert(MemberTeamMap("M3","T3"))
dao.insert(MemberTeamMap("M4","T3"))
dao.insert(MemberTeamMap("M5","T3"))
// Extract the Teams and their members :-
for(twm: TeamWithMembers in dao.getAllTeamsWithMember()) {
Log.d(tag,"Team is ${twm.team.name}")
for(m: Member in twm.members) {
Log.d(tag,"\tMember is ${m.name}")
}
}
如果以上运行,那么日志将包括: -
D/TEAMDBINFO: Team is Team1
D/TEAMDBINFO: Member is Member1
D/TEAMDBINFO: Member is Member3
D/TEAMDBINFO: Member is Member5
D/TEAMDBINFO: Team is Team2
D/TEAMDBINFO: Member is Member2
D/TEAMDBINFO: Member is Member4
D/TEAMDBINFO: Team is Team3
D/TEAMDBINFO: Member is Member1
D/TEAMDBINFO: Member is Member2
D/TEAMDBINFO: Member is Member3
D/TEAMDBINFO: Member is Member4
D/TEAMDBINFO: Member is Member5
D/TEAMDBINFO: Team is Team4