2015-10-23 59 views
2

我正在使用Slick 3和Play! 2.4我有一個很常見的問題,我無法解決。油滑3多對多的關係:如何獲得表格的所有元素及其關係(如果存在)?

我有一個表playlist可以通過關係表playlistsTracks的幫助鏈接到一些軌道。我希望能夠通過他們的曲目關係和曲目獲得所有播放列表。我的問題是,如果他們沒有任何關係,我就無法獲得播放列表。

這裏有3個表:

class Playlists(tag: Tag) extends Table[Playlist](tag, "playlists") { 
    def id = column[Long]("playlistid", O.PrimaryKey, O.AutoInc) 
    def name = column[String]("name") 

    def * = (id.?, name) <> ((Playlist.apply _).tupled, Playlist.unapply) 
    } 

class PlaylistsTracks(tag: Tag) extends Table[PlaylistTrack](tag, "playliststracks") { 
    def playlistId = column[Long]("playlistid") 
    def trackId = column[UUID]("trackid") 
    def trackRank = column[Double]("trackrank") 

    def * = (playlistId, trackId, trackRank) <> ((PlaylistTrack.apply _).tupled, PlaylistTrack.unapply) 

    def aFK = foreignKey("playlistId", playlistId, playlists)(_.id, onDelete = ForeignKeyAction.Cascade) 
    def bFK = foreignKey("trackId", trackId, tracks)(_.uuid, onDelete = ForeignKeyAction.Cascade) 
    } 

class Tracks(tag: Tag) extends Table[Track](tag, "tracks") { 
    def uuid = column[UUID]("trackid", O.PrimaryKey) 
    def title = column[String]("title") 

    def * = (uuid, title) <> ((Track.apply _).tupled, Track.unapply) 
    } 

眼下的代碼片段,讓播放列表看起來像這樣:

val query = for { 
    playlist <- playlists 
    playlistTrack <- playlistsTracks if playlistTrack.playlistId === playlist.id 
    track <- tracks if playlistTrack.trackId === track.uuid 
} yield (playlist, playlistTrack, track) 

db.run(query.result) map { println } 

它打印像Vector(Playlist, PlaylistTrack, Track)(我想),但我只是讓播放列表擁有關係,而不是獲取所有播放列表,即使是沒有關係的播放列表也是如我所願。

我嘗試了很多像使用join(或joinFull,joinLeft,joinRight ...)但沒有成功的事情,但不幸的是很難找到一些不僅非常容易關係的示例項目。

+0

如果你想要所有的播放列表,那麼當你有播放列表值但沒有播放列表曲目或曲目時,應該「生成」什麼?換句話說,你想(播放列表1,無,無)只是播放列表1 ...? –

+0

是的(播放列表1,無,無)會很好:然後我將它映射到我的PlaylistWithTracks案例類(看起來像這樣:(播放列表:播放列表,tracksWithRank:Seq [TrackWithRank]) – Simon

+0

我能想到的唯一解決方案是做3個單獨的查詢,並在應用程序中執行「加入」邏輯(而不是服務器端)。是否可以接受? –

回答

5

您需要在Playlists和PlaylistTracks表之間使用左連接,並在PlaylistTracks和Tracks之間使用內連接。 有一些東西,在這個例子裏缺,所以我不能實際編譯如下,但我認爲你可以嘗試這樣的:

val query = for { 
    (playlist, optionalPlaylistTrackAndTrack) <- playlists joinLeft (playlistsTracks join tracks on (_.trackId === _.uuid)) on (_.id === _._1.playlistId) 
} yield (playlist, optionalPlaylistTrackAndTrack) 

注意optionalPlaylistTrackAndTrack是一個元組的代表播放列表軌道和一個選項跟蹤。這是因爲可能存在沒有播放列表跟蹤的播放列表。

+0

它似乎完全符合我的需求,並且它沒有任何改變地編譯;)謝謝! – Simon