【问题标题】:Slick and nesting case classes a no go?光滑和嵌套案例类不行吗?
【发布时间】:2014-08-19 03:50:30
【问题描述】:

我正在使用 slick(和 play 框架)在现有数据库之上构建应用程序。我无法更改数据库结构。

我的数据库有以下 2 个表:

会议:

  • id (PK)
  • 姓名
  • chairman_id(FK 到 Person.id)
  • houseman_id(FK 到 Person.id)

人:

  • id (pk)
  • 名字
  • 姓氏

我想像这样定义我的案例类:

case class Meeting (
  id: Int,
  name: String,
  chairman: Person,
  houseman: Person
) 

case class Person (
   id: Int,
   firstName: String,
   lastName: String
)

但是从关于这个的非常简洁的文档来看,看起来我必须将 ID 保留在案例类中,而不是使用“Person”。那是对的吗?

最好的方法是什么?抱歉这个相对开放的问题,对 scala 来说很新,很流畅。

谢谢,

埃德

【问题讨论】:

    标签: scala playframework playframework-2.0 slick slick-2.0


    【解决方案1】:

    您有外键,它们不会转换为案例类,它们会转换为 id:

    case class Meeting (
      id: Int,
      name: String,
      chairmanId: Int,
      housemanId: Int) 
    
     case class Person (
      id: Int,
      firstName: String,
      lastName: String)
    

    架构类似于:

     case class Meeting (
                       id: Int,
                       name: String,
                       chairmanId: Int,
                       housemanId: Int)
    
     case class Person (
                      id: Int,
                      firstName: String,
                      lastName: String)
    
    
    class Meetings(tag: Tag) extends Table[Meeting](tag, "meeting") {
      def * = (id, name, chairmanId, housemanId) <>(Meeting.tupled, Meeting.unapply)
    
      def ? = (id.?, name, chairmanId, housemanId).shaped.<>({
        r => import r._
          _1.map(_ => Meeting.tupled((_1.get, _2, _3, _4)))
      }, (_: Any) => throw new Exception("Inserting into ? projection not supported."))
    
      val id: Column[Int] = column[Int]("id", O.AutoInc, O.PrimaryKey)
      val name: Column[String] = column[String]("name")
      val chairmanId: Column[Int] = column[Int]("chairmanId")
      val housemanId: Column[Int] = column[Int]("housemanId")
    
      lazy val meetingChairmanFk =
        foreignKey("meeting_chairman_fk", chairmanId, persons)(r => r.id, onUpdate = ForeignKeyAction.Restrict, onDelete = ForeignKeyAction.Cascade)
    
    
      lazy val meetingHousemanFk =
        foreignKey("meeting_houseman_fk", housemanId, persons)(r => r.id, onUpdate = ForeignKeyAction.Restrict, onDelete = ForeignKeyAction.Cascade)
    
    
    }
    
    lazy val meetings = new TableQuery(tag => new Meetings(tag))
    
    class Persons(tag: Tag) extends Table[Person](tag, "person") {
      def * = (id, firstName, lastName) <>(Person.tupled, Person.unapply)
    
      def ? = (id.?, firstName, lastName).shaped.<>({
        r => import r._
          _1.map(_ => Person.tupled((_1.get, _2, _3)))
      }, (_: Any) => throw new Exception("Inserting into ? projection not supported."))
    
      val id: Column[Int] = column[Int]("id", O.AutoInc, O.PrimaryKey)
      val firstName: Column[String] = column[String]("firstname")
      val lastName: Column[String] = column[String]("lastname")
    
    
    }
    
    lazy val persons = new TableQuery(tag => new Persons(tag))
    

    它可以这样使用:

    val thisMeeting = meetings.filter(_.name === "thisMeeting").join(persons).on((m, p) => m.housemanId === p.id || m.chairmanId === p.id).list()
    

    或用于理解(我个人觉得更清晰):

    val thatMeething = (for {
      m <- meetings
      p <- persons if (p.id === m.chairmanId || p.id === m.housemanId) && m.name === "thatMeeting"
    } yield m.id).run
    

    注意第二个查询对应一个隐式内连接,其他类型的连接也支持,你可以找到here

    【讨论】:

    • 感谢 Ende,我确实有一个与此非常相似的模型,但我不确定加载链接对象的方法应该是什么。因此,如果我加载会议,我也希望加载相关的 2 人。我是否必须通过连接查询将这些作为元组加载?
    • 我在答案中添加了一个示例。
    • 是的,爱德华,您需要像 SQL 中那样的连接查询。不同之处在于您可以将其放入一个函数中并与其他查询组合起来。因此,基本上该查询片段就是您的关系映射,因为您只需指定一次并在需要的地方使用它。
    • cvogt,我可以看到您已经多次在 SO 上给出了这个答案,但我仍然不相信从开发人员的角度来看这是有道理的。我们不必围绕持久层构建数据。
    • dbaumann 我完全同意你的看法。我只是将此作为框架的限制。因此,我希望摆脱 slick。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-26
    • 1970-01-01
    • 1970-01-01
    • 2011-05-27
    • 2018-08-03
    • 2015-04-24
    • 1970-01-01
    相关资源
    最近更新 更多