在某些情况下,我需要能够通过提供除
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)
}
问题的根源在于超载的
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)
}
一种可能的解决方案是将
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)
}
注意:使用内部原子 long 作为 id 生成器而不是使用自动增量序列生成器 数据库提供,因为它们可以安全地防止并发访问 多个应用程序。
现在回到代码,tupled方法在函数上定义,并将具有N个参数的函数转换为具有单个参数的函数,N个元组
从您的描述来看,重载 apply 方法似乎会导致编译器无法确定应选择哪个“apply”实现。因此,您可能应该做两件事: