Liftことはじめ その6 mapper ManyToMany
前述の記事の覚書
LiftのORMでManyToManyを実装。
AlbumとTrack間で実装。(同一Trackが、複数のAlbumに収録される事実を踏まえ。regular Albumとbest AlbumのTrack共用。)
まずは、Albumクラス。
model/Album.scala
package code.model import net.liftweb.mapper._ import net.liftweb.util._ import net.liftweb.common._ object Album extends Album with LongKeyedMetaMapper[Album] { override def dbTableName = "albums" } class Album extends LongKeyedMapper[Album] with IdPK with ManyToMany with OneToMany[Long, Album] { def this(albumtitle: String) = { this() this.albumtitle(albumtitle) } def getSingleton = Album object albumtitle extends MappedString(this, 100) { override def validations = valMaxLen(100, "message must be under 100 characters long ") _ :: valMinLen(1, "you have to input") _ :: super.validations } object band extends LongMappedMapper(this, Band) def getBand(): Band = { Band.findAll(By(Band.id, band.get)).head } object tracks extends MappedManyToMany(AlbumTracks, AlbumTracks.album, AlbumTracks.track, Track, OrderBy(AlbumTracks.seq, Ascending)) object albumTracks extends MappedOneToMany(AlbumTracks, AlbumTracks.album, OrderBy(AlbumTracks.seq, Ascending)) }
(Albumクラスが、OneToManyトレイトもmixinしているのは、AlbumTracksクラスとOneToManyのアソシエーションを構成しているため)
続いて、Trackクラス
package code.model import net.liftweb.mapper._ import net.liftweb.util._ import net.liftweb.common._ object Track extends Track with LongKeyedMetaMapper[Track] { override def dbTableName = "tracks" } class Track extends LongKeyedMapper[Track] with IdPK with ManyToMany with OneToMany[Long, Track] { def this(seq: Long, tracktitle: String) = { this() this.tracktitle(tracktitle) } def getSingleton = Track object tracktitle extends MappedString(this, 100) { override def validations = valMaxLen(100, "name length must be under 100 characters long ") _ :: valMinLen(1, "you have to input!!") _ :: super.validations } object albums extends MappedManyToMany(AlbumTracks, AlbumTracks.track, AlbumTracks.album, Album) object attaches extends MappedOneToMany(Attach, Attach.track, OrderBy(Attach.id, Ascending)) object albumTracks extends MappedOneToMany(AlbumTracks, AlbumTracks.track, OrderBy(AlbumTracks.album, Ascending)) }
(Trackクラスが、OneToManyトレイトもmixinしているのは、AtachクラスとOneToManyのアソシエーションを構成しているため)
最後に、AlbumTracksクラス
model/AlbumTracks.scala
package code.model import net.liftweb.mapper._ import net.liftweb.util._ import net.liftweb.common._ object AlbumTracks extends AlbumTracks with LongKeyedMetaMapper[AlbumTracks] class AlbumTracks extends LongKeyedMapper[AlbumTracks] with IdPK { def this(album: Long, track: Long, seq: Long) = { this() this.seq(seq) this.album(album) this.track(track) } def getSingleton = AlbumTracks object album extends LongMappedMapper(this, Album) object track extends LongMappedMapper(this, Track) object seq extends MappedLong(this) def getTrack(): Track = Track.findAll(By(Track.id, track.get)).head def setSeq(seq: Long): Unit = {this.seq(seq)} }
ちょっと悩んだのは、IdPKトレイトをmixinしたこと、ManyToManyを構成する分には、
不要であるが、Aubum、Track間のアソシエーションを削除するためにmixinした。
以下は、利用のためのコード
(登録、更新)
album.tracks += track album.save
と実装すればよいのだが、seq(曲順)の属性をAlbumTracksの属性にしたかったので、個別にインスタンス化した。
val albumTrack: AlbumTracks = AlbumTracks.create.album(albumid.toLong).track(track.id.get).seq(seq.toLong) albumTrack.save
(削除)
val album = Album.findAll(By(Album.id, getAlbumId().toLong)).head album.tracks -= track album.save