【问题标题】:How do I model a relational database link-table with Scala?如何使用 Scala 对关系数据库链接表进行建模?
【发布时间】:2012-07-15 18:42:35
【问题描述】:

我需要在 Scala 中对对象进行很多多对多映射并将其保存到关系数据库中。

这是一个简化问题的假例子:

假设我们要为教室和学生建模。一个教室可能有很多学生,但这些学生也可以去不同的房间。从关系数据库模型的角度来看,您将创建 3 张表,一张用于 ROOM,一张用于 STUDENT,一张用于链接学生和房间,ROOM_STUDENT。

假设表格如下所示:

ROOM
-----
id
subject

STUDENT
-------
id
name

ROOM_STUDENT
-------------
room_id
student_id

如果我想使用 Scala 来访问(并可能创建)这样的数据库,那么如何使用 ScalaQuery 或 SLICK 来做到这一点,或者是否有更好的 Scala 解决方案?我应该以某种方式使用案例类,还是以某种方式使用普通的旧 SQL?

我基本上希望在这里得到两个提示,1. 一种在 Scala 中呈现 STUDENT 和 ROOM 的好方法,2. 针对此问题的关系数据库持久性的一些想法。

【问题讨论】:

    标签: scala scalaquery


    【解决方案1】:

    我个人更喜欢 Lift's Mapper library,并且偶尔会在 Lift Web 应用程序的上下文之外使用它。以下是一个完整的工作示例,您可以从 sbt 运行它,例如将以下内容作为您的 build.sbt

    libraryDependencies ++= Seq(
      "net.liftweb" %% "lift-mapper" % "2.4" % "compile->default",
      "com.h2database" % "h2" % "1.2.127"
    )
    

    首先是模型:

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

    还有一些数据库设置:

    DB.defineConnectionManager(
      DefaultConnectionIdentifier,
      new StandardDBVendor("org.h2.Driver", "jdbc:h2:mem:example", Empty, Empty)
    )
    
    Schemifier.schemify(true, Schemifier.infoF _, Student, Room, StudentRoom)
    

    还有一些数据:

    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
    

    我们准备好了:

    scala> Room.findAll(By(Room.subject, "Physics")).flatMap(_.students)
    res7: List[Student] = List(Student={name=Mary,id=2}, Student={name=John,id=3})
    

    【讨论】:

    • 非常感谢特拉维斯。我以前没有使用过电梯。你知道我可以添加到 build.sbt 以仅使用映射器的最小存储库吗?例如,如果我想用 SBT 运行您的示例?有趣的一点是:“net.liftweb”%%“lift-mapper”%liftVersion%“compile->default”。我来自:assembla.com/wiki/show/liftweb/Using_SBT
    • @JacobusR:我添加了一个编辑,其中包含您在配置中需要的一行。
    • Travis,你将如何删除链接表记录? IE。你如何删除创建的记录:StudentRoom.create.student(m).room(physics).save
    • 如果你有StudentRoom 对象,你可以调用它的delete_! 方法。如果没有,您可以查找该对象然后将其删除:StudentRoom.find(By(StudentRoom.room, physics), By(StudentRoom.student, m)).map(_.delete_!)
    • 啊,让我困惑的是查找。 By... By... bit ;-) 再次感谢 Travis!
    猜你喜欢
    • 2017-09-10
    • 1970-01-01
    • 2022-01-11
    • 2012-03-24
    • 2013-04-06
    • 1970-01-01
    • 1970-01-01
    • 2010-12-06
    相关资源
    最近更新 更多