I need to do quite a few many to many mapping of objects in Scala and save it to a relational database.
Here is a fake example to simplify the problem:
Let's say we want to model lecture rooms and students. A lecture room may have many students, but those students can also go to different rooms. From a relational database model point of view, you would create 3 tables, one for ROOM, one for STUDENT and one to link students and rooms, ROOM_STUDENT.
Let's say the tables look like this:
ROOM
-----
id
subject
STUDENT
-------
id
name
ROOM_STUDENT
-------------
room_id
student_id
If I want to use Scala to access (and maybe create) such a database, how will one do this with, say, ScalaQuery or SLICK, or is there a better Scala solution? Should I use case classes with this in some way, or just plain old SQL in some way or another?
I'm basically hoping for two hints here, 1. a good way to present the STUDENT and ROOM in Scala, 2. some ideas towards relational database persistence for this problem.
I personally prefer Lift's Mapper library for this, and have occasionally used it outside of the context of a Lift web application. The following is a complete working example, which you can run from sbt
for example with the following as your build.sbt
:
libraryDependencies ++= Seq(
"net.liftweb" %% "lift-mapper" % "2.4" % "compile->default",
"com.h2database" % "h2" % "1.2.127"
)
First for the models:
import net.liftweb.common._, net.liftweb.mapper._
object Student extends Student with LongKeyedMetaMapper[Student]
class Student extends LongKeyedMapper[Student] with IdPK with ManyToMany {
def getSingleton = Student
object name extends MappedString(this, 40)
object rooms extends MappedManyToMany(
StudentRoom, StudentRoom.student, StudentRoom.room, Room
)
}
object Room extends Room with LongKeyedMetaMapper[Room]
class Room extends LongKeyedMapper[Room] with IdPK with ManyToMany {
def getSingleton = Room
object subject extends MappedString(this, 40)
object students extends MappedManyToMany(
StudentRoom, StudentRoom.room, StudentRoom.student, Student
)
}
object StudentRoom extends StudentRoom with LongKeyedMetaMapper[StudentRoom] {
override def dbIndexes = Index(student, room) :: super.dbIndexes
}
class StudentRoom extends LongKeyedMapper[StudentRoom] with IdPK {
def getSingleton = StudentRoom
object student extends MappedLongForeignKey(this, Student)
object room extends MappedLongForeignKey(this, Room)
}
And some database setup:
DB.defineConnectionManager(
DefaultConnectionIdentifier,
new StandardDBVendor("org.h2.Driver", "jdbc:h2:mem:example", Empty, Empty)
)
Schemifier.schemify(true, Schemifier.infoF _, Student, Room, StudentRoom)
And some data:
val m = Student.create.name("Mary"); m.save
val j = Student.create.name("John"); j.save
val physics = Room.create.subject("Physics"); physics.save
StudentRoom.create.student(m).room(physics).save
StudentRoom.create.student(j).room(physics).save
And we're ready:
scala> Room.findAll(By(Room.subject, "Physics")).flatMap(_.students)
res7: List[Student] = List(Student={name=Mary,id=2}, Student={name=John,id=3})