我还没有尝试过,但是你混合的特征怎么样:
trait CommonFields { this: Table[_] =>
def id = column[String]("id", O.PrimaryKey)
def livemode = column[Boolean]("livemode", O.NotNull)
def created = column[DateTime]("created", O.NotNull)
def createdBy = column[Account]("created_by", O.NotNull)
protected common_* = id ~ livemode ~ created ~ createdBy
}
那么你可以这样做:
object AsTable extends Table[(String,Boolean,DateTime,Account,String)]("a_table")
with CommonFields {
def foo = column[String]("foo", O.NotNull)
def * = common_* ~ foo
}
您现在唯一需要重复的是元素的类型。
更新
如果你想做对象映射并且:
- 您映射到案例类
- 案例类中的字段顺序相同
只要做:
case class A(
id: String,
livemode: Boolean,
created: DateTime,
createdBy: Account,
foo: String)
object AsTable extends Table[A]("a_table") with CommonFields {
def foo = column[String]("foo", O.NotNull)
def * = common_* ~ foo <> (A.apply _, A.unapply _)
}
这似乎是最经济的解决方案(而不是尝试在CommonFields 中定义* 并添加类型参数)。但是,如果您的字段发生变化,则需要您更改所有案例类别。
我们可以尝试通过在案例类上使用组合来缓解这种情况:
case class Common(
id: String,
livemode: Boolean,
created: DateTime,
createdBy: Account)
case class A(
common: Common,
foo: String)
但是,在构造映射器函数时,我们将(在某处)最终不得不转换以下形式的元组:
(CT_1, CT_2, ... CT_N, ST_1, ST_2, ..., ST_M)
CT 通用类型(已知于CommonFields)
ST 特定类型(已知于AsTable)
收件人:
(CT_1, CT_2, ... CT_N), (ST_1, ST_2, ..., ST_M)
为了将它们传递给子例程,将Common 和A 单独转换为它们的元组。
我们必须在不知道CT(在AsTable 中实现时)或ST(在CommonFields 中实现时)的数量或确切类型的情况下执行此操作。 Scala 标准库中的元组无法做到这一点。您需要使用HLists 提供的示例shapeless 来执行此操作。
这是否值得努力值得怀疑。
基本轮廓可能看起来像这样(不需要所有隐含的混乱)。这段代码不会这样编译。
trait CommonFields { this: Table[_] =>
// like before
type ElList = String :: Boolean :: DateTime :: Account :: HNil
protected def toCommon(els: ElList) = Common.apply.tupled(els.tupled)
protected def fromCommon(c: Common) = HList(Common.unapply(c))
}
object AsTable extends Table[A] with CommonFields {
def foo = column[String]("foo", O.NotNull)
def * = common_* ~ foo <> (x => toA(HList(x)), x => fromA(x) tupled)
// convert HList to A
protected def toA[L <: HList](els: L) = {
// Values for Common
val c_els = els.take[Length[ElList]]
// Values for A
val a_els = toCommon(c_els) :: els.drop[Length[ElList]]
A.apply.tupled(a_els.tupled)
}
// convert A to HList
protected def fromA(a: A) =
fromCommon(a.common) :: HList(A.unapply(a)).drop[One]
}
使用更多的类型魔法,您可能可以解决最后两个问题:
- 将
toA 和fromA 放入基本特征(通过在特征中使用类型参数,或使用抽象类型成员)
- 避免通过使用this technique从
Common.apply中提取ElList来显式定义它