Mapped projection with <> to a case class with companion object in Slick

≡放荡痞女 提交于 2019-12-04 13:13:04

问题


With Slick, I am trying to project database table entries directly to the case class they represent. Following the example in the documentation, I set up a mapped projection using the <> operator:

case class SomeEntity3(id: Int, entity1: Int, entity2: Int)

val SomeEntityTable = new Table[SomeEntity3]("some_entity_table") {
  def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
  def entity1 = column[Int]("entity1")
  def entity2 = column[Int]("entity2")

  def * = id ~ entity1 ~ entity2 <> (SomeEntity3, SomeEntity3.unapply _)
}

Now, I'd like to add some static constants and auxiliary methods to SomeEntity3. For that, I create a companion object. But as soon as I include the line

object SomeEntity3

a pretty wild multi-line error pops up for the definition of * saying something illegible about "overloaded method value <> with alternatives".

How does the companion object relate to bi-directional mapping in Slick and can I somehow accomplish my goal?


回答1:


Companion objects of case classes usually are a function from the case class' first argument list to the case class. So if you had

case class Fnord(a: A, b: B, c: C)(d: D)

the Scala compiler would autogenerate the companion object similar to

object Fnord extends ((A, B, C) => Fnord) {
  ...
}

Now, as soon as you explicitly spell out something about the companion object yourself, the compiler no longer generates the FunctionN extending thingy. Thus, most of the time it is a good idea to add it yourself. In your case that would mean defining the companion of SomeEntity3 like so:

object SomeEntity3 extends ((Int, Int, Int) => SomeEntity3) {
  ...
}

There's a (long open) issue for this behaviour, too: https://issues.scala-lang.org/browse/SI-3664




回答2:


The fix is quite simple:

def * = id ~ entity1 ~ entity2 <> (SomeEntity3.apply _, SomeEntity3.unapply _)



回答3:


Another way to do it is to turn the objects apply method into a tuple and pass that to the <> as shown below.

package models

import play.api._
import play.api.libs.json._
import scala.slick.driver.H2Driver.simple._

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

object User {
  implicit val format = Json.format[User]
}

class UserTable(tag: Tag) extends Table[User](tag, "USERS") {
  def id = column[Int]("ID", O.PrimaryKey, O.AutoInc)
  def name = column[String]("NAME", O.NotNull)

  def * = (name, id.?) <> ((User.apply _).tupled, User.unapply)
}

object Users extends TableQuery(new UserTable(_)) {
  val findByID = this.findBy(_.id)
}



回答4:


Personally, the partially applied apply method from the case class does not work with my setup and Slick 3.0.

This however, works, burrowing to the proper tupled method indirectly:

class WidgetTable(tag: Tag) extends Table[WidgetEntity](tag, "widget_tbl") {

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

    override def * = (id,foo) <> ((WidgetEntity.apply _).tupled,WidgetEntity.unapply)
}

See the full details: https://stackoverflow.com/a/38589579/564157



来源:https://stackoverflow.com/questions/15175659/mapped-projection-with-to-a-case-class-with-companion-object-in-slick

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!