Slick:CRUD扩展:如何封装隐式映射:BaseColumnType [T]

时间:2014-11-24 20:58:40

标签: scala refactoring slick slick-2.0 scalaquery

Slick CRUD有以下API(Slick-2.1.0,Scala-2.11.4):

trait HasId {
  type Id
  def id: Option[Id]
}
trait HasIdColumn[E <: HasId] {
  def id: scala.slick.lifted.Column[E#Id]
}
trait SlickExtensions {
    val driver: scala.slick.driver.JdbcProfile
    import driver.simple._

    trait BaseDAO[T <: Table[E], E] {
      val query: TableQuery[T]
    }
    trait HasIdActions[T <: Table[E] with HasIdColumn[E], E <: HasId] 
      extends BaseDAO[T, E] {
      //line L1: this implicit val is needed to execute query.filter(_.id === id)
      // what can be done in order to save the user from the necessity 
      // to override this value?
      implicit val mappingId: BaseColumnType[E#Id]

      def findById(id: E#Id)(implicit session: Session): Option[E] = 
          query.filter(_.id === id).firstOption
      ...
    }
}

我按如下方式应用此SlickExtensions:

case class Entity(id: Option[Long] = None, value: String) extends HasId { 
   type Id = Long }

trait EntityComponent extends SlickExtensions {
    import driver.simple._

    class EntitiesTable(tag: Tag) extends Table[Entity](tag, "entities") 
     with HasIdColumn[Entity] {
      def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
      def value = column[String]("value", O.NotNull)
      def * = (id.?, value) <>(Entity.tupled, Entity.unapply)
    }

    object Entities extends HasIdActions[EntitiesTable, Entity] {
      val query = TableQuery[EntitiesTable]
      /* line L2: from slick library: ImplicitColumnTypes */
      override implicit val mappingId = driver.simple.longColumnType
    }
  }

执行查询的终点:

val c = new EntityComponent {
    lazy val driver = play.api.db.slick.Config.driver
}

db.withSession { implicit session =>
    c.Entities.findById(1) foreach println
}

主要问题是如何摆脱&#34;隐式val mappingId&#34;在第L2行覆盖?

我试图创建一个类:

abstract class IdImplicits[E<:HasId](implicit val mappingId:BaseColumnType[E#Id])

并继承如下:

object Entities extends IdImplicits[EntitiesTable, Entity] 
   with HasIdActions[EntitiesTable, Entity] {
      val query = TableQuery[EntitiesTable]
      //override implicit val mappingId: driver.simple.longColumnType
}

然而,在我看来,这种方法是多余的。 如果我可以隐藏&#34;隐式val mappingId&#34;那将是很好的。在SlickExtensions内部。

Here is the link to the same question


UPD:

在我的项目中,我想添加HasName,HasValue [V]和其他一些mixin来构建以下DAO:

object EntitiesDAO extends HasIdActions 
  with HasNameActions 
  with HasValueActions with NameToIdActions with ValueToIdActions {
    ...
    override def nameToId(name:String):Option[E#Id]
    override def valueToId(value:E#ValueType):Option[E#Id]
    ...
}

导致以下问题:

1)对于HasId,HasValue mixins

,我的主题中提到的BaseColumnTypes的含义应该被考虑在内

2)如果implicits将BaseColumnTypes用作抽象类构造函数的参数,则这些类不能混合在一个EntityDAO对象(the problem is described here)中。

3)如果EntityDAO的每个变体都使用了一个抽象类,那么我们会得到丑陋的组合,例如:

abstract class IdValueNameImplicits[E <: HasId with HasValue with HasName]
     (implicit val idMapper:BaseColumnType[E#Id], 
      implicit val valueMapper:BaseColumnType[E#ValueType])

1 个答案:

答案 0 :(得分:1)

你不能这样做,因为你在一个特质内,而E#Id仅在你具体实施时定义。

正如您已经发现的那样,您必须在实现特征时定义BaseColumnType,因为只有这样您才能为E#Id定义类型。

另一个选择是没有特征,而是一个抽象类,你可以将一个隐式的BaseColumnType传递给构造函数。

我有一个小项目,可以完全满足您的需求。您可以在此处找到它:https://github.com/strongtyped/active-slick

还有一个Activator模板。 http://typesafe.com/activator/template/slick-active-record

您可以按原样使用它,也可以将它作为您自己的灵感。

玩得开心!