重载`apply`方法时:光滑的错误消息“值元组不是对象的成员”

问题描述 投票:0回答:3

在某些情况下,我需要能够通过提供除

User
之外的所有值来创建
id
对象,以便
User
对象负责为自己分配一个自动生成的值。

为此,我重载了伴生对象中的 apply 方法,如下所示。但这会导致编译时错误:

value tupled is not a member of object

StackOverflow 和其他博客上提到的解决方案不起作用,例如: 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)

}
scala slick
3个回答
12
投票

问题的根源在于超载的

apply
def。

tupled
不适用于
case class
less than 2 parameters
overloaded apply

就 slick 的

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

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

这样,

  • func1
    将元组
    (tupleMember1, tupleMember2, ...)
    作为输入并返回映射类/案例类的实例。
  • func2
    获取映射类/案例类的实例并返回该元组
    (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)

}

1
投票

一种可能的解决方案是将

secondary constructor
推送到
case class
定义本身,然后使用问题中指定的博客文章中提到的解决方法。

然后您可以创建

User
对象而不指定
id
,但是,您可能仍然需要使用
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)

}

0
投票

注意:使用内部原子 long 作为 id 生成器而不是使用自动增量序列生成器 数据库提供,因为它们可以安全地防止并发访问 多个应用程序。

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

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

  1. 重命名第二个apply(一般情况下,请避免重载)
  2. 显式调用 tupled(即 User.withEmptyId.tupled)
© www.soinside.com 2019 - 2024. All rights reserved.