Slick:避免asInstanceOf [T]和改进类型签名

时间:2016-02-08 04:52:47

标签: scala generics slick

下面的代码有效,但我不禁想到我正在做一些不合适的asInstanceOf[B]演员。

基本上,在传递某种类型的TableQuery之后,我希望mapper变成一个动作,然后根据一个函数将map变成一个DAO列表传递给它。

我坚持的是函数的类型,或者可能是如何公开TableQuery类型的内部类型。我想做一些像[B <: TableElementType] f: B => A这样的事情,而不是对B的可能残酷演员。

我想我认为我知道我将在下面的示例中获得类似AgencyRow的内容以映射到AgencyDAO,我如何在方法的类型签名中捕获它?


映射

  def mapper[A <: BaseDAO, B <: DatabaseAccessObject, T <: TableQuery[E], E <: AbstractTable[_]](query: T, f: B => A) : Seq[A] = {
    val result = exec(query.result)
    result.map(o => f(o.asInstanceOf[B]))
  }

  def exec[T](action: DBIO[T]): T = Await.result(db.run(action), 4 seconds)

使用Mapper(测试代码)

val list = mapper[AgencyDAO, AgencyRow, TableQuery[Agency], Agency](agencies, AgencyDAODomainObject.convertFromRow)
        list.length should equal(75)

Slick Schema

case class AgencyRow(id: Int, name: Option[String] = None) extends DatabaseAccessObject

class Agency(_tableTag: Tag) extends Table[AgencyRow](_tableTag, "agency") {
   def * = (id, name) <>(AgencyRow.tupled, AgencyRow.unapply)
   def ? = (Rep.Some(id), name).shaped.<>({ r => import r._; _1.map(_ => AgencyRow.tupled((_1.get, _2))) }, (_: Any) => throw new Exception("Inserting into ? projection not supported."))

   val id: Rep[Int] = column[Int]("id", O.AutoInc, O.PrimaryKey)
   val name: Rep[Option[String]] = column[Option[String]]("name", O.Length(200, varying = true), O.Default(None))
}

lazy val Agency = new TableQuery(tag => new Agency(tag))enter code here

DAO Mapper

package object Implicits {
   implicit class DomainObjectOps[A <: BaseDAO](a: A)(implicit ev: DomainObject[A]) {
   def name = ev.name(a)
   def id = ev.id(a)
  }
}   

trait BaseDAO
trait DomainObject[A <: BaseDAO] {
  def id(a: A): Int
  def name(a: A): String
}

case class AgencyDAO(val id: Int, val name: String) extends BaseDAO
object AgencyDAO {
  implicit object AgencyDAODomainObject extends DomainObject[AgencyDAO] {
    def convertToRow(o: AgencyDAO) = AgencyRow(o.id, Some(o.name))
    def convertFromRow(o: AgencyRow) = AgencyDAO(o.id, o.name.getOrElse(""))

    override def id(a: AgencyDAO) = a.id
    override def name(a: AgencyDAO) = a.name
  }
}

1 个答案:

答案 0 :(得分:0)

如果其他人可能会发现这个相关或有启发性:而不是在映射器内的查询上调用result,而是传入已调用的result,返回{{1} }。 Slick有一个方便的别名DBIOAction[R],可以要求DBIO[R]扩展R,无需播放。所以现在:

更新了Mapper

Seq[B]

更新了呼叫

def resultMapper[A <: BaseDAO, B <: DatabaseAccessObject, S <: DBIO[Seq[B]]](action: S)(implicit rowMapper: B => A) : Seq[A] = {
   val result = exec(action)
   result.map(rowMapper)
}