英文:
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("SELECT * FROM playListEntity")
fun getAll(): LiveData<List<PlayListWithSong>>
答案1
得分: 4
如果您在所有的dao
类中将插入函数的返回类型定义为Long
,您就能够获取插入的项目的ID,然后将此ID用于在PlayListWithSongs
中插入。例如:
@Dao
interface SongDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(entity: Song): Long
}
更新:
请注意,Song
和Playlist
是两个不同的实体。因此,虽然您想要将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 = "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
)
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论