Java 如何将数据插入多对多表室(Sql)android

Java 如何将数据插入多对多表室(Sql)android,java,android,mysql,kotlin,android-room,Java,Android,Mysql,Kotlin,Android Room,我创建了这个表,但我不知道如何将数据添加到PlayWithSongs表中 @实体 数据类实体( var songId:Long?=null, 变量名称:字符串?=null, ) @实体 数据类实体( 变量playlid:Long?=null, 变量名称:字符串?=null ) 这里如何将ID插入PlayWithSongs表 但在我的情况下,播放列表可能有相同的歌曲或是空的。即使是歌曲也会出现在一个播放列表、无播放列表或多个播放列表中,因此如何插入带有歌曲的播放列表实体。由于这两个ID都是主键

我创建了这个表,但我不知道如何将数据添加到PlayWithSongs表中

@实体
数据类实体(
var songId:Long?=null,
变量名称:字符串?=null,
)
@实体
数据类实体(
变量playlid:Long?=null,
变量名称:字符串?=null
)
这里如何将ID插入PlayWithSongs表


但在我的情况下,播放列表可能有相同的歌曲或是空的。即使是歌曲也会出现在一个播放列表、无播放列表或多个播放列表中,因此如何插入带有歌曲的播放列表实体。由于这两个ID都是主键,并且播放列表中没有歌曲,因此会出现null并包含重复项(此处歌曲列表和课程大小列表不相似)

@Insert
趣味插曲(播放歌曲:播放歌曲)
@插入(onConflict=OnConflictStrategy.REPLACE)
趣味插入播放列表(播放列表:播放实体?)
@插入(onConflict=OnConflictStrategy.REPLACE)
趣味插入课程(歌曲:SongsEntity?)
@交易
@查询(“从播放列表实体中选择*)
fun getAll():LiveData

如果在所有
dao
类中将插入函数的返回类型定义为
Long
,则可以获取插入项的id,然后使用此id插入
播放歌曲。例如:

@Dao
interface SongDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(entity: Song): Long
}
更新: 请注意,
歌曲
播放列表
是两个不同的实体。因此,当您想要将一首歌曲
分配给一个播放列表(这意味着在包含歌曲的歌曲中添加一个新行)时,目标歌曲和播放列表应该存在于db中

我的意思是,你永远不会尝试将一首尚未存在的歌曲添加到播放列表中。因此,在创建播放列表的第一刻,没有为其分配歌曲。这意味着
playliwithsongs
表中没有包含新创建的
playliID
的行

总之,很明显,当您想要将歌曲分配给播放列表时,您应该同时拥有这两个ID。另外,最好不要将这对组合用作歌曲播放的主键。让我们看看我写的关于这个主题的代码:

@Entity(
    tableName = "playListWithSongs",
    foreignKeys = [
        ForeignKey(
            entity = Song::class,
            parentColumns = ["songId"],
            childColumns = ["songId"],
            onDelete = CASCADE
        ),
        ForeignKey(
            entity = Playlist::class,
            parentColumns = ["playlistId"],
            childColumns = ["playlistId"],
            onDelete = CASCADE
        )
    ],
    indices = [
        Index(
            value = ["songId", "playlistId"],
            unique = true
        )
    ]
)
data class PlayListWithSongs(
    @PrimaryKey(autoGenerate = true) val id: Int? = null,
    @ColumnInfo(name = "songId") val songId: Long,
    @ColumnInfo(name = "playlistId") val playlistId: Long
)

正如您在上面的代码中所看到的,如果一首歌曲或播放列表被删除,则其在
playliwithsongs
上的所有分配也会被删除(由于
级联
)。因此,不必担心未使用的行和重复(请注意,songId和PlayID的组合被定义为唯一的)。

oth,您可以在不映射的情况下执行此操作。创建两个实体,一个用于歌曲,另一个用于包含歌曲的播放列表,而不是映射,将歌曲id保留为播放列表中的列表对象,并从播放列表中相应地查询包含id的歌曲表。以下是您如何实现这一目标的方法-


然而,我确实更喜欢传统的映射,因为@aminography在他的答案中被证实,这样你就可以利用
级联
操作将父键上的删除或更新操作传播到每个从属子键。

但是在我的情况下,播放列表可能有相同的歌曲或是空的。即使歌曲会出现在一个播放列表、无播放列表或多个播放列表中,那么我如何插入歌曲实体的播放列表。由于这两个ID都是主键,并且一个播放列表中没有歌曲,因此会出现null并包含重复内容(此处歌曲列表和课程大小列表不相似)@14编程:我已更新答案。请查看。我建议您信任此结构:)每个播放列表可以有零到任意数量的歌曲。此外,任何数量的播放列表中的每首歌曲都可以归零。它正确地提供了多对多关系,没有任何重复。请注意,复制是指[1,5]和[1,5]等[PlayID,songId]的重复对,由于
索引(value=[“songId”,“PlayID”],unique=true)
而无法存在。没问题,请放心。请在插入和检索时共享代码。
@Dao
interface SongDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(entity: Song): Long
}
@Entity(
    tableName = "playListWithSongs",
    foreignKeys = [
        ForeignKey(
            entity = Song::class,
            parentColumns = ["songId"],
            childColumns = ["songId"],
            onDelete = CASCADE
        ),
        ForeignKey(
            entity = Playlist::class,
            parentColumns = ["playlistId"],
            childColumns = ["playlistId"],
            onDelete = CASCADE
        )
    ],
    indices = [
        Index(
            value = ["songId", "playlistId"],
            unique = true
        )
    ]
)
data class PlayListWithSongs(
    @PrimaryKey(autoGenerate = true) val id: Int? = null,
    @ColumnInfo(name = "songId") val songId: Long,
    @ColumnInfo(name = "playlistId") val playlistId: Long
)