重载 `apply` 方法时:光滑的错误消息 'value tupled is not a member of object'

When overloading `apply` method: Slick error message 'value tupled is not a member of object'

我需要能够通过在某些情况下提供除 id 之外的所有值来创建 User 对象,这样 User 对象负责为自己分配一个自动-产生的价值。

为此,我重载了伴随对象中的 apply 方法,如下所示。但这会导致编译时错误:value tupled is not a member of object.

Whosebug 和其他博客中提及的解决方案均无效,例如: http://queirozf.com/entries/slick-error-message-value-tupled-is-not-a-member-of-object

case class User(id: Long, firstName: String, lastName: String, mobile: Long, email: String)

object User {
  private val seq = new AtomicLong

  def apply(firstName: String, lastName: String, mobile: Long, email: String): User = {
    User(seq.incrementAndGet(), firstName, lastName, mobile, email)
  }
}

class UserTableDef(tag: Tag) extends Table[User](tag, "user") {

  def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
  def firstName = column[String]("first_name")
  def lastName = column[String]("last_name")
  def mobile = column[Long]("mobile")
  def email = column[String]("email")

  override def * =
    (id, firstName, lastName, mobile, email) <> (User.tupled, User.unapply)

}

Notice: It is probably a bad idea to use an internal atomic long as an id generator instead of using auto-increment sequence generator that database provide, as these are safe against concurrent access from multiple applications.

现在回到代码,tupled 方法定义在函数上,并将具有 N 个参数的函数 转换为函数使用 单个 参数,N 元元组

根据您的描述,似乎重载 apply 方法会导致编译器无法确定应选择哪个 "apply" 实现。因此,您可能应该做两件事:

  1. 重命名第二个应用程序(一般情况下,请避免重载)
  2. 明确调用元组(即User.withEmptyId.tupled)

一种可能的解决方案是将 secondary constructor 推送到 case class 定义本身,然后使用问题中指定的博客 post 中提到的解决方法。

然后您可以在不指定 id 的情况下创建 User 对象,但是,您可能仍需要使用 new 关键字,例如 new User(firstName, lastName, mobile, email).

case class User(id: Long, firstName: String, lastName: String, mobile: Long, email: String) {

  def this(firstName: String, lastName: String, mobile: Long, email: String) =
    this(User.seq.incrementAndGet(), firstName, lastName, mobile, email)
}

object User {
  private val seq = new AtomicLong
}

class UserTableDef(tag: Tag) extends Table[User](tag, "user") {

  def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
  def firstName = column[String]("first_name")
  def lastName = column[String]("last_name")
  def mobile = column[Long]("mobile")
  def email = column[String]("email")

  override def * =
    (id, firstName, lastName, mobile, email) <> ((User.apply _).tupled, User.unapply)

}

你的问题的根源是 apply def.

过载

tupled 不适用于 case classless than 2 parametersoverloaded apply

就 slick 的 *(或全部)映射和 <> 而言,它应该是这样的,

def * = (tupleMember1, tupleMember2, ...) <> (func1, func2)

这样,

  • func1 将元组 (tupleMember1, tupleMember2, ...) 作为输入,returns 是映射 class/case class.
  • 的一个实例
  • func1 获取映射 class/case class 和 returns 元组 (tupleMember1, tupleMember2, ...).
  • 的实例

因此您可以提供满足这些要求的任何功能...

case class User(id: Long, firstName: String, lastName: String, mobile: Long, email: String)

object User {
  private val seq = new AtomicLong

  def apply(firstName: String, lastName: String, mobile: Long, email: String): User = {
    User(seq.incrementAndGet(), firstName, lastName, mobile, email)
  }

  def mapperTo(
    id: Long, firstName: String,
    lastName: String, mobile: Long, email: String
  ) = apply(id, firstName, lastName, mobile, email)

}

class UserTableDef(tag: Tag) extends Table[User](tag, "user") {

  def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
  def firstName = column[String]("first_name")
  def lastName = column[String]("last_name")
  def mobile = column[Long]("mobile")
  def email = column[String]("email")

  override def * =
    (id, firstName, lastName, mobile, email) <> ((User.mapperTo _).tupled, User.unapply)

}