如何为嵌套案例类列表创建光滑投影?

时间:2017-11-09 11:12:31

标签: scala slick

我正在使用播放2.6.6 scala 2.12.3 slick 3.0.0

我最初有以下案例类结构,其中有一个嵌套的案例类:

case class Device(id: Int, deviceUser: Option[DeviceUser] =None)

case class DeviceUser(name: Option[String] = None)

所以,我为设备类创建了以下投影:

class DevicesTable(tag: Tag) extends Table[Device](tag, "DEVICES") {

    def id = column[Int]("ID", O.PrimaryKey)

    def name = column[Option[String]]("NAME")

    def deviceUser = name.<>[Option[DeviceUser]](
      {
        (param: Option[String]) => {
          param match {
            case Some(name) => Some(DeviceUser(Some(name)))
            case None => None
          }
        }
      },
      {
        (t: Option[DeviceUser]) =>
         {
           t match {
             case Some(user) => Some(user.name)
             case None => None
           }
         }
      }
    )

    def * = (id, deviceUser).<>(Device.tupled, Device.unapply)
  }

上面的设置工作正常。我可以使用上面的投影轻松存储和检索数据。 But now, my requirement has changed and I need to store list of nested case class。所以,类结构现在如下:

case class Device(id: Int, deviceUser: Option[List[DeviceUser]] =None)

case class DeviceUser(name: Option[String] = None)

是否有某种方法可以为字段 deviceUser定义投影:选项[List [DeviceUser]]

更新:我正在寻找更多non-relational方法。

1 个答案:

答案 0 :(得分:0)

因为到目前为止,还没有人提出过解决方案,我现在正在分享我正在使用的方法。它有效,但当然不是最好的解决方案。特别是,我想避免在这里使用Await,并希望开发generic implicit parser

另外,我必须创建一个单独的DeviceUsersTable

    case class DeviceUser(id: Int,name: Option[String] = None)

    class DeviceUserRepo @Inject()(protected val dbConfigProvider: DatabaseConfigProvider)  {

      val dbConfig = dbConfigProvider.get[JdbcProfile]
      val db = dbConfig.db
      import dbConfig.profile.api._
      val DeviceUsers = TableQuery[DeviceUserTable]

      private def _findById(id: Int): DBIO[Option[DeviceUser]] =
        DeviceUsers.filter(_.id === id).result.headOption

      def findById(id: Int): Future[Option[DeviceUser]] =
        db.run(_findById(id))

      def all: Future[List[DeviceUser]] =
        db.run(DeviceUsers.to[List].result)

      def create(deviceUser: DeviceUser): Future[Int] = {
        db.run(DeviceUsers returning DeviceUsers.map(_.id) += deviceUser)
      }

      class DeviceUserTable(tag: Tag) extends Table[DeviceUser](tag, "DEVICE_USERS") {

        def id = column[Int]("ID", O.PrimaryKey)
        def name = column[Option[String]]("NAME")
        def * = (id, name).<>(DeviceUser.tupled, DeviceUser.unapply)
      }

    }

原来的DevicesTable现在看起来像这样:

class DevicesTable(tag: Tag) extends Table[Device](tag, "DEVICES") {

    implicit val deviceUserConverter = MappedColumnType.base[Option[List[DeviceUser]], String](
      deviceUsersOpt => {
        deviceUsersOpt match {
          case Some(users:List[DeviceUser]) =>val listOfId = users.map{
            k => val res = deviceUserRepo.create(k)
              Await.result(res, 10 seconds)
          }
            listOfId.mkString(",")
          case None => ""
        }
      },
      str =>{
        val listOfIds = (str split "," map Integer.parseInt).toList.filterNot(k => k.equals(""))
        if(listOfIds.nonEmpty){
          val users = listOfIds.map{ k =>
            val res = deviceUserRepo.findById(k)
            Await.result(res, 10 seconds)
          }
          Some(users.flatten)
        } else {
          None
        }
      }
    )

    def id = column[Int]("ID", O.PrimaryKey)

    def deviceUser = column[Option[List[DeviceUser]]]("DEVICE_USERS")

    def * = (id, deviceUser).<>(Device.tupled, Device.unapply)
  }