如何向多对多表中插入数据 – Room(Sql)Android

huangapple go评论83阅读模式
英文:

How to insert data to many to many table - room(Sql) android

问题

我创建了这个表格,但我不知道如何向 playListWithSongs 表中添加数据。

<!-- language: lang-html -->

@Entity
data class SongEntity(
  var songId : Long? = null,
  var name: String? = null,
)

<!-- end snippet -->


<!-- language: lang-html -->

@Entity
data class playlistEntity(
  var playListId : Long? = null,
  var playlistName: String? = null
)

<!-- end snippet -->

@Entity
data class playListWithSongs(
     var playlistId: Long,
     var songId: Long
)


这里该如何将 ids 插入到 playListWithSongs 表中?

但在我的情况下,播放列表可能有相同的歌曲或为空。即使歌曲存在于一个播放列表中,也可能没有播放列表,或者有多个播放列表,那么我该如何插入 PlayListWithSongs 实体呢?由于两个 ids 都是主键,并且对于某个播放列表,我可能会有零首歌曲,因此会出现空值并且包含重复(这里歌曲列表和课程列表的大小不相似)


@Insert
fun insert(playListSong: playListWithSongs)

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertPlayList(playList: PlayListEntity?)

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertCourse(song: SongsEntity?)

@Transaction
@Query("SELECT * FROM playListEntity")
fun getAll(): LiveData<List<PlayListWithSong>>
英文:

I created this table but i don't know how to add the data to the playListWithSongs table.

<!-- language: lang-html -->

@Entity
data class SongEntity(
  var songId : Long? = null,
  var name: String? = null,
 )

<!-- end snippet -->

<!-- language: lang-html -->

@Entity
data class playlistEntity(
  var playListId : Long? = null,
  var playlistName: String? = null
)

<!-- end snippet -->

@Entity
data class playListWithSongs(
     var playlistId: Long,
     var songId: Long
)

Here How to insert the ids to the playListWithSongs table?

But in my case, the playlist may have the same songs or empty. Even songs will be present in one playlist , no playlist or many playlist so how can I insert the PlayListWithSongs Entity. Since both ids are primary key and I will have zero songs for a playlist there will be null and contains duplication (Here the list of song and list of course Size are not similar)

@Insert
fun insert(playListSong: playListWithSongs)

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertPlayList(playList: PlayListEntity?)

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertCourse(song: SongsEntity?)

@Transaction
@Query(&quot;SELECT * FROM playListEntity&quot;)
fun getAll(): LiveData&lt;List&lt;PlayListWithSong&gt;&gt;

答案1

得分: 4

如果您在所有的dao类中将插入函数的返回类型定义为Long,您就能够获取插入的项目的ID,然后将此ID用于在PlayListWithSongs中插入。例如:

@Dao
interface SongDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(entity: Song): Long
}

更新:

请注意,SongPlaylist是两个不同的实体。因此,虽然您想要将Song分配给Playlist(这意味着在playListWithSongs中添加一个新行,其中包含它们的ID),但目标歌曲和播放列表应该在数据库中存在。

我的意思是,您永远不会尝试将歌曲添加到尚不存在的播放列表中。因此,在播放列表被创建的第一刻,没有歌曲被分配给它。这意味着在playListWithSongs表中没有具有新创建的播放列表的playlistId的行。

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

@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
)

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

英文:

If you define the return type of the insert functions as Long in all of your dao classes, you will be able to get the id of the inserted item, then use this id for inserting in PlayListWithSongs. For example:

@Dao
interface SongDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(entity: Song): Long
}

Update:

Note that the Song and the Playlist are two distinct entities. So, while you want to assign a Song to a Playlist (which means adding a new row in playListWithSongs containing both their ids), the target song and playlist should exist in db.

I mean you would never try to add a song to a playlist which has not existed yet. So, At the first moment that a playlist gets created, there is no song assigned to it. It means that there is no row in the playListWithSongs table with the playlistId of the newly created one.

To sum up, it is obvious that when you want to assign a song to a playlist, you should have both ids. Also, it's better to not to use this couple as the primary key for the playListWithSongs. Let's see my written code for this subject:

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

As you can see in the above code, if a song or playlist gets removed, all of its assignments on playListWithSongs get removed too (due to CASCADE). So there is no concern about unused rows and duplication (Note that the combination of songId and playlistId is defined as unique).

答案2

得分: 0

然而,我更倾向于传统的映射,正如 @aminography 在他的回答中所详细阐述的那样,这样你就可以利用“级联(CASCADE)”操作来将对父键的删除或更新操作传播到每个相关的子键。

英文:

OTOH, You can do it without mapping. Create two entity one for songs another one for playlist with songs, instead of mapping keep the song id's as a list object in the playlist, and query the song table with the id's from the playlist accordingly. Here is how you can achieve that - https://medium.com/@toddcookevt/android-room-storing-lists-of-objects-766cca57e3f9.

Nevertheless, I do prefer the conventional mapping as @aminography eloborated in his answer so that u can make use of CASCADE action to propagate the delete or update operation on the parent key to each dependent child key.

huangapple
  • 本文由 发表于 2020年9月11日 19:03:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/63845814.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定