这个问题是问题How to define an abstract copyable superclass for any case class的结果,但人们可以单独留下这个背景,并专注于此:
注意:可以在github play-authenticate-usage-scala
中访问整个编译代码库(使用Scala 2.11.8)我有一个使用shapeless的特性并被定义为(注意implicit mkLens
):
import shapeless._, tag.@@
import shapeless._
import tag.$at$at
trait AutoIncEntity[PK, E <: AutoIncEntity[PK, E]] extends Entity[PK] { self: E =>
def copyWithNewId(id : PK)(implicit mkLens: MkFieldLens.Aux[E, Symbol @@ Witness.`"id"`.T, PK]) : E = {
(lens[E] >> 'id).set(self)(id)
}
}
所有复杂性基本上都是这样说的:任何案例类(如Slick自动生成的那些行)通过扩展此特征,提供copyWithNewId(id)
的基本可重用实现。此方法只是委托给copy(id = id)
方法,该方法是生成的案例类编译器,不能抽象出来或“拉出”#34;。例如,通过扩展UserRow
AutoIncEntity
可以用作构建在AutoIncEntity
之上的框架的一部分:
case class UserRow(id: Long, firstName: Option[String] = None,
middleName: Option[String] = None, lastName: Option[String] = None)
extends AutoIncEntity[Long, UserRow]
现在我使用AutoIncEntity
构建一个插入新记录的通用Dao,同时从数据库中提取用户实体,包括新生成的自动id
:
abstract class GenericDaoAutoIncImpl[T <: Table[E] with IdentifyableTable[PK], E <: AutoIncEntity[PK, E], PK: BaseColumnType]
(dbConfigProvider: DatabaseConfigProvider, tableQuery: TableQuery[T]) extends GenericDaoImpl[T, E, PK](dbConfigProvider, tableQuery)
with GenericDaoAutoInc[T, E, PK] {
override def createAndFetch(entity: E)(implicit mkLens: MkFieldLens.Aux[E, Symbol @@ Witness.`"id"`.T, PK]): Future[Option[E]] = {
val insertQuery = tableQuery returning tableQuery.map(_.id) into ((row, id) => row.copyWithNewId(id))
db.run((insertQuery += entity).flatMap(row => findById(row.id)))
}
}
现在的问题是如何修改此解决方案以避免传播/复制粘贴&#34; voodoo&#34;隐式参数(implicit mkLens: MkFieldLens.Aux[E, Symbol @@ Witness.
&#34; id&#34; .T, PK])
?和相应的需要&#34; voodoo&#34;进口?