【问题标题】:Combining embedded entities with one-to-many entities将嵌入式实体与一对多实体相结合
【发布时间】:2021-04-11 11:44:10
【问题描述】:

我有以下运动情况:
每场比赛正好有2支球队。每支球队都有很多球员。
因为我需要知道哪个团队是第一和哪个团队,所以我创建了这样的实体:

@Entity
data class MatchEntity(
    @PrimaryKey
    val matchId: String,
    @Embedded(prefix = "firstTeam_")
    val firstTeam: TeamDetailedWithPlayers,
    @Embedded(prefix = "secondTeam_")
    val secondTeam: TeamDetailedWithPlayers,
)

data class TeamDetailedWithPlayers(
    @Embedded
    val team: TeamDetailedEntity,
    @Relation(
        parentColumn = "id",
        entityColumn = "teamId",
    )
    val players: List<PlayerEntity>
)

@Entity
data class TeamDetailedEntity(
    @PrimaryKey
    val id: String,
    /* ... */
)

@Entity
data class PlayerEntity(
    @PrimaryKey
    val id: String,
    val teamId: String,
    /* ... */
)

现在,当我尝试构建它时,由于前缀,我收到以下错误:
Cannot find the parent entity column `id` in TeamDetailedWithPlayers. Options: firstTeam_id, ...

有没有(其他)方法可以优雅地解决这个问题,而不涉及 MatchEntity 内部团队的显式外键?

【问题讨论】:

    标签: android android-room entity-relationship


    【解决方案1】:

    我相信您正在混合应该是 POJO 和应该是实体的内容,并且基本上是在尝试存储重复数据和存储需要不必要的类型转换器的数据。

    • 如果使用@Entity,那么它定义了一个表,如果没有,那么它是一个 POJO

    例如,比赛应该有一个 matchId,也许还有其他比赛特定数据以及对第一和第二队的引用,而不是试图在比赛实体中嵌入和复制整个时间信息和球员。

    所以表(实体)你想要一个 Match 表,其中包含 2 个团队中的每一个的引用,一个团队表和一个包含该玩家所在团队的玩家表。

    然后您就有了 POJO,例如 TeamWithPlayers 和 MatchWithTeams。例如,对于表结构(架构),您可以:-

    • 注意 id 使用 Longs(更高效)
    • 注意 id 名称是唯一的,而不仅仅是 id(重复的列可能会导致列不明确的问题)

    团队实体

    @Entity
    data class TeamEntity(
        @PrimaryKey
        val teamId: Long,
        val teamName: String
        /*
            other Team detail here
         */
    )
    

    玩家实体

    @Entity
    data class PlayerEntity(
        @PrimaryKey
        val playerId: Long,
        @ForeignKey(entity = TeamEntity::class,parentColumns = ["teamId"],childColumns = ["teamReference"])
        val teamReference: Long,
        val playerName: String
        /*
            other player info here
         */
    )
    

    MatchEntity

    @Entity
    data class MatchEntity(
        @PrimaryKey
        val matchId: Long,
        @ForeignKey(entity = TeamEntity::class, parentColumns = ["matchId"],childColumns = ["firstTeamReference"])
        val firstTeamReference: Long,
        @ForeignKey(entity = TeamEntity::class, parentColumns = ["matchId"],childColumns = ["secondTeamReference"])
        val secondTeamReference: Long
    )
    

    如果没有任何 POJO,这将创建一个看起来像(通过 Database Inspector)的数据库:-

    • 可以看出编译成功。

    然后您可以使用简单的 Dao 插入一些测试数据,然后处理 Dao 和 POJO 以获得您想要的数据。

    带有玩家列表的团队 POJO 示例,即 TeamWithPlayers:-

    data class TeamWithPlayers(
        @Embedded
        val teamEntity: TeamEntity,
        @Relation(entity = PlayerEntity::class,parentColumn = "teamId",entityColumn = "teamReference")
        val playerlist: List<PlayerEntity>
    )
    

    与 2 个 TeamWithPlayers 匹配的示例 POJO:-

    data class MatchWithTeamsWithPlayers(
        @Embedded
        val matchEntity: MatchEntity,
        @Relation(entity = TeamEntity::class, parentColumn = "firstTeamReference",entityColumn = "teamId")
        val firstTeam: List<TeamWithPlayers>,
        @Relation(entity = TeamEntity::class,parentColumn = "secondTeamReference",entityColumn = "teamId")
        val secondTeam: List<TeamWithPlayers>
    )
    

    工作示例

    AllDao

    中的第一道
    @Dao
    interface AllDao {
    
        @Insert
        fun insertTeamEntity(teamEntity: TeamEntity): Long
        @Insert
        fun insertPlayerEntity(playerEntity: PlayerEntity): Long
        @Insert
        fun insertMatchEntity(matchEntity: MatchEntity): Long
        @Query("SELECT count(*) FROM teamentity")
        fun getTeamCount(): Long
        @Query("SELECT * FROM teamentity")
        fun getAllTeamsWithPlayers(): List<TeamWithPlayers>
        @Query("SELECT * FROM matchEntity")
        fun getAllMatchesWithTeamdsWithPlayers(): List<MatchWithTeamsWithPlayers>
    }
    

    接下来是数据库SportsDatabase:-

    @Database(entities = [TeamEntity::class,PlayerEntity::class,MatchEntity::class],version = 1)
    abstract class SportsDatabase: RoomDatabase() {
        abstract fun getDao(): AllDao
    }
    

    最终通过 Activity MainActivity 进行测试(参见 cmets)

    • 为了方便和简洁,请注意在主线程上进行的测试

    :-

    class MainActivity : AppCompatActivity() {
        lateinit var db: SportsDatabase
        lateinit var dao: AllDao
        val TAG = "SPORTDBINFO"
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            // STAGE 1 create and populate the data base using just the core schema no POJO's
            db = Room.databaseBuilder(this,SportsDatabase::class.java,"mysports.db")
                .allowMainThreadQueries()
                .build()
            dao = db.getDao()
    
    
            // Add some testing data but only if none exists (any Team row existing as the check)
            if (dao.getTeamCount() < 1) {
                
                // 3 teams
                dao.insertTeamEntity(TeamEntity(1, "Team 1"))
                dao.insertTeamEntity(TeamEntity(2, "Team 2"))
                dao.insertTeamEntity(TeamEntity(3, "Team 3"))
    
                // 3 players per team except team 3 with 2 playes
                dao.insertPlayerEntity(PlayerEntity(100, 1, "Player 100 in Team 1"))
                dao.insertPlayerEntity(PlayerEntity(101, 1, "Player 101 in Team 1"))
                dao.insertPlayerEntity(PlayerEntity(102, 1, "Player 102 in Team 1"))
                dao.insertPlayerEntity(PlayerEntity(200, 2, "Player 200 in Team 2"))
                dao.insertPlayerEntity(PlayerEntity(201, 2, "Player 201 in Team 2"))
                dao.insertPlayerEntity(PlayerEntity(202, 2, "Player 202 in Team 2"))
                dao.insertPlayerEntity(PlayerEntity(300, 3, "Player 300 in Team 3"))
                dao.insertPlayerEntity(PlayerEntity(301, 3, "Player 301 in Team 3"))
    
                // some matches each team plays each team home and away i.e. 6 matches
                dao.insertMatchEntity(MatchEntity(1000, 1, 2))
                dao.insertMatchEntity(MatchEntity(1010, 2, 3))
                dao.insertMatchEntity(MatchEntity(1020, 1, 3))
                dao.insertMatchEntity(MatchEntity(500, 3, 1))
                dao.insertMatchEntity(MatchEntity(510, 3, 2))
                dao.insertMatchEntity(MatchEntity(520, 2, 3))
            }
    
            // Stage 2 check the use of the TeamWithPlayers POJO using the getAllTeamWithPlayers PJOJO
            for (team: TeamWithPlayers in dao.getAllTeamsWithPlayers()) {
                logTeam( team.teamEntity)
                for (player: PlayerEntity in team.playerlist) {
                    logPlayer(player)
                }
            }
    
            // Stage 3 check the use of the MatchWithTeamsWithPlayers POJO
            for(match: MatchWithTeamsWithPlayers in dao.getAllMatchesWithTeamdsWithPlayers()) {
                logMatch(match.matchEntity)
                // First team
                for(team: TeamWithPlayers in match.firstTeam) {
                    logTeam(team.teamEntity)
                    // players in the first team
                    for(player: PlayerEntity in team.playerlist) {
                        logPlayer(player)
                    }
                }
                // Second team
                for(team: TeamWithPlayers in match.secondTeam) {
                    logTeam(team.teamEntity)
                    // players in the second team
                    for(player: PlayerEntity in team.playerlist) {
                        logPlayer(player)
                    }
                }
            }
        }
    
        private fun logPlayer(playerEntity: PlayerEntity) {
            Log.d(TAG,"\t\tPlayer Name = " + playerEntity.playerName + " PlayerID =" + playerEntity.playerId + " TeamReference = " + playerEntity.teamReference)
        }
        private fun logTeam(teamEntity: TeamEntity) {
            Log.d(TAG,"\tTeam Name =" + teamEntity.teamName + " TeamID = " + teamEntity.teamId)
        }
        private fun logMatch(matchEntity: MatchEntity) {
            Log.d(TAG,"Match ID = " + matchEntity.matchId + " Team 1 reference = " + matchEntity.firstTeamReference + " Team 2 reference = " + matchEntity.secondTeamReference)
        }
    }
    

    结果即输出到日志

    2021-04-11 13:26:06.555 D/SPORTDBINFO:  Team Name =Team 1 TeamID = 1
    2021-04-11 13:26:06.555 D/SPORTDBINFO:      Player Name = Player 100 in Team 1 PlayerID =100 TeamReference = 1
    2021-04-11 13:26:06.555 D/SPORTDBINFO:      Player Name = Player 101 in Team 1 PlayerID =101 TeamReference = 1
    2021-04-11 13:26:06.555 D/SPORTDBINFO:      Player Name = Player 102 in Team 1 PlayerID =102 TeamReference = 1
    2021-04-11 13:26:06.555 D/SPORTDBINFO:  Team Name =Team 2 TeamID = 2
    2021-04-11 13:26:06.555 D/SPORTDBINFO:      Player Name = Player 200 in Team 2 PlayerID =200 TeamReference = 2
    2021-04-11 13:26:06.555 D/SPORTDBINFO:      Player Name = Player 201 in Team 2 PlayerID =201 TeamReference = 2
    2021-04-11 13:26:06.555 D/SPORTDBINFO:      Player Name = Player 202 in Team 2 PlayerID =202 TeamReference = 2
    2021-04-11 13:26:06.555 D/SPORTDBINFO:  Team Name =Team 3 TeamID = 3
    2021-04-11 13:26:06.555 D/SPORTDBINFO:      Player Name = Player 300 in Team 3 PlayerID =300 TeamReference = 3
    2021-04-11 13:26:06.555 D/SPORTDBINFO:      Player Name = Player 301 in Team 3 PlayerID =301 TeamReference = 3
    
    
    
    
    2021-04-11 13:26:06.562 D/SPORTDBINFO: Match ID = 500 Team 1 reference = 3 Team 2 reference = 1
    2021-04-11 13:26:06.562 D/SPORTDBINFO:  Team Name =Team 3 TeamID = 3
    2021-04-11 13:26:06.562 D/SPORTDBINFO:      Player Name = Player 300 in Team 3 PlayerID =300 TeamReference = 3
    2021-04-11 13:26:06.562 D/SPORTDBINFO:      Player Name = Player 301 in Team 3 PlayerID =301 TeamReference = 3
    2021-04-11 13:26:06.562 D/SPORTDBINFO:  Team Name =Team 1 TeamID = 1
    2021-04-11 13:26:06.562 D/SPORTDBINFO:      Player Name = Player 100 in Team 1 PlayerID =100 TeamReference = 1
    2021-04-11 13:26:06.562 D/SPORTDBINFO:      Player Name = Player 101 in Team 1 PlayerID =101 TeamReference = 1
    2021-04-11 13:26:06.562 D/SPORTDBINFO:      Player Name = Player 102 in Team 1 PlayerID =102 TeamReference = 1
    2021-04-11 13:26:06.562 D/SPORTDBINFO: Match ID = 510 Team 1 reference = 3 Team 2 reference = 2
    2021-04-11 13:26:06.563 D/SPORTDBINFO:  Team Name =Team 3 TeamID = 3
    2021-04-11 13:26:06.563 D/SPORTDBINFO:      Player Name = Player 300 in Team 3 PlayerID =300 TeamReference = 3
    2021-04-11 13:26:06.563 D/SPORTDBINFO:      Player Name = Player 301 in Team 3 PlayerID =301 TeamReference = 3
    2021-04-11 13:26:06.563 D/SPORTDBINFO:  Team Name =Team 2 TeamID = 2
    2021-04-11 13:26:06.563 D/SPORTDBINFO:      Player Name = Player 200 in Team 2 PlayerID =200 TeamReference = 2
    2021-04-11 13:26:06.563 D/SPORTDBINFO:      Player Name = Player 201 in Team 2 PlayerID =201 TeamReference = 2
    2021-04-11 13:26:06.563 D/SPORTDBINFO:      Player Name = Player 202 in Team 2 PlayerID =202 TeamReference = 2
    2021-04-11 13:26:06.563 D/SPORTDBINFO: Match ID = 520 Team 1 reference = 2 Team 2 reference = 3
    2021-04-11 13:26:06.563 D/SPORTDBINFO:  Team Name =Team 2 TeamID = 2
    2021-04-11 13:26:06.563 D/SPORTDBINFO:      Player Name = Player 200 in Team 2 PlayerID =200 TeamReference = 2
    2021-04-11 13:26:06.563 D/SPORTDBINFO:      Player Name = Player 201 in Team 2 PlayerID =201 TeamReference = 2
    2021-04-11 13:26:06.564 D/SPORTDBINFO:      Player Name = Player 202 in Team 2 PlayerID =202 TeamReference = 2
    2021-04-11 13:26:06.564 D/SPORTDBINFO:  Team Name =Team 3 TeamID = 3
    2021-04-11 13:26:06.564 D/SPORTDBINFO:      Player Name = Player 300 in Team 3 PlayerID =300 TeamReference = 3
    2021-04-11 13:26:06.564 D/SPORTDBINFO:      Player Name = Player 301 in Team 3 PlayerID =301 TeamReference = 3
    2021-04-11 13:26:06.564 D/SPORTDBINFO: Match ID = 1000 Team 1 reference = 1 Team 2 reference = 2
    2021-04-11 13:26:06.564 D/SPORTDBINFO:  Team Name =Team 1 TeamID = 1
    2021-04-11 13:26:06.564 D/SPORTDBINFO:      Player Name = Player 100 in Team 1 PlayerID =100 TeamReference = 1
    2021-04-11 13:26:06.564 D/SPORTDBINFO:      Player Name = Player 101 in Team 1 PlayerID =101 TeamReference = 1
    2021-04-11 13:26:06.564 D/SPORTDBINFO:      Player Name = Player 102 in Team 1 PlayerID =102 TeamReference = 1
    2021-04-11 13:26:06.564 D/SPORTDBINFO:  Team Name =Team 2 TeamID = 2
    2021-04-11 13:26:06.564 D/SPORTDBINFO:      Player Name = Player 200 in Team 2 PlayerID =200 TeamReference = 2
    2021-04-11 13:26:06.565 D/SPORTDBINFO:      Player Name = Player 201 in Team 2 PlayerID =201 TeamReference = 2
    2021-04-11 13:26:06.565 D/SPORTDBINFO:      Player Name = Player 202 in Team 2 PlayerID =202 TeamReference = 2
    2021-04-11 13:26:06.565 D/SPORTDBINFO: Match ID = 1010 Team 1 reference = 2 Team 2 reference = 3
    2021-04-11 13:26:06.565 D/SPORTDBINFO:  Team Name =Team 2 TeamID = 2
    2021-04-11 13:26:06.565 D/SPORTDBINFO:      Player Name = Player 200 in Team 2 PlayerID =200 TeamReference = 2
    2021-04-11 13:26:06.565 D/SPORTDBINFO:      Player Name = Player 201 in Team 2 PlayerID =201 TeamReference = 2
    2021-04-11 13:26:06.565 D/SPORTDBINFO:      Player Name = Player 202 in Team 2 PlayerID =202 TeamReference = 2
    2021-04-11 13:26:06.565 D/SPORTDBINFO:  Team Name =Team 3 TeamID = 3
    2021-04-11 13:26:06.565 D/SPORTDBINFO:      Player Name = Player 300 in Team 3 PlayerID =300 TeamReference = 3
    2021-04-11 13:26:06.565 D/SPORTDBINFO:      Player Name = Player 301 in Team 3 PlayerID =301 TeamReference = 3
    2021-04-11 13:26:06.565 D/SPORTDBINFO: Match ID = 1020 Team 1 reference = 1 Team 2 reference = 3
    2021-04-11 13:26:06.565 D/SPORTDBINFO:  Team Name =Team 1 TeamID = 1
    2021-04-11 13:26:06.566 D/SPORTDBINFO:      Player Name = Player 100 in Team 1 PlayerID =100 TeamReference = 1
    2021-04-11 13:26:06.566 D/SPORTDBINFO:      Player Name = Player 101 in Team 1 PlayerID =101 TeamReference = 1
    2021-04-11 13:26:06.566 D/SPORTDBINFO:      Player Name = Player 102 in Team 1 PlayerID =102 TeamReference = 1
    2021-04-11 13:26:06.566 D/SPORTDBINFO:  Team Name =Team 3 TeamID = 3
    2021-04-11 13:26:06.566 D/SPORTDBINFO:      Player Name = Player 300 in Team 3 PlayerID =300 TeamReference = 3
    2021-04-11 13:26:06.566 D/SPORTDBINFO:      Player Name = Player 301 in Team 3 PlayerID =301 TeamReference = 3
    

    【讨论】:

    • 应用程序的性质使得重复不是(真的)问题。团队很少会被重复使用,并且很容易被删除,比如每周一次。因此,我想使用@Embedded,因为它提供了一个更简单的界面。但是,因为看起来我不可能接受你的建议。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-31
    • 2015-01-26
    • 1970-01-01
    • 1970-01-01
    • 2012-10-17
    相关资源
    最近更新 更多