【问题标题】:Slick: Avoiding asInstanceOf[T] and Improving Type signatureSlick:避免 asInstanceOf[T] 并改进类型签名
【发布时间】:2016-05-17 16:42:27
【问题描述】:

下面的代码有效,但我不禁认为我对 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)

使用映射器(测试代码)

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

Slick 架构

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 映射器

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
  }
}

【问题讨论】:

  • 您在mapped 的第一行中使用的TableQuery.result 的签名是什么?我似乎找不到its definition
  • @dcastro 所以,我的理解是它是 DBIOAction 的一个实例,但它是特定于数据库驱动程序的(通过导入适当的 api 公开)所以你最终会得到类似 PostgresDriver.StreamingDriverAction 的东西

标签: scala generics slick


【解决方案1】:

万一其他人可能会发现这相关或有启发性:与其在映射器内的查询上调用result,不如通过已经调用的result 传入,它返回一个DBIOAction[R]。 Slick 有一个方便的别名DBIO[R],并且可以要求R 扩展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)
}

更新调用

implicit val rowMapper: AgencyRow => AgencyDAO = AgencyDAODomainObject.convertFromRow
val action = agencies.result //turns query to DBIOAction
val list = resultMapper[AgencyDAO, AgencyRow, DBIO[Seq[AgencyRow]]](action) 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多