如何定义受多个隐式转换影响的类型?

How to define a type that is subject to several implicit conversions?

我正在使用 slick 3.0。我只是想将一些数据库设置代码集中到一个特征中。

以下是我的资料:

import slick.driver.H2Driver.api._
import scala.concurrent.Await
import scala.concurrent.duration.Duration

object EventFixtures {

  val table = TableQuery[EventsTable]
  val data = Seq(...)

  def insertFixtures(db: Database): Int = {

    Await.result(db.run(table.schema.create), Duration.Inf)  
    Await.result(db.run(table ++= data), Duration.Inf).get
  }
}

我已经将其提升并转移到特征中:

import slick.driver.H2Driver.api._

import scala.concurrent.Await
import scala.concurrent.duration.Duration


trait FixtureHelper {

  val data: Seq
  val table: ???

  def insertFixtures(db: Database) = {

    Await.result(db.run(table.schema.create), Duration.Inf)
    Await.result(db.run(table ++= data), Duration.Inf).get
  }
}

我想像这样使用它:

object EventFixtures extends FixtureHelper {
  val data = Seq(...)
  val table = TableQuery[EventsTable]
}

// in test code:
EventFixtures.insertFixtures()

问题是 table 的类型。

  1. table 的类型为:slick.lifted.TableQuery[_ <: AbstractTable],并且仅当我使用此类型时才会找到行 ++=,但无论如何都不会发生 seq 的隐式转换。
  2. table.schema 具有类型:slick.profile.RelationalProfile#TableQueryExtensionMethods,如果我按照第 1 点声明 table,则找不到此 属性。
  3. table.schema.create 具有类型:slick.driver.JdbcActionComponent$SchemaActionExtensionMethodsImpl,如果我按照第 2 点声明 table,则找不到此 属性。

在原始代码中,table 被实例化为 TableQuery,slick 使用一些隐式转换来添加其他属性。它还必须将 data seq 转换为 E#TableElementType.

的 Iterable

那么我如何才能通用地键入 table 以便编译此特征并且可以找到所有这些隐式添加的成员?

我认为这会很简单,但似乎除非我用具体的 class 实例化 TableQuery,否则整个事情就会分崩离析。事实上,在我不同的 fixture 文件中,我确实用具体的 table 实例化了 TableQuery,所以我只需要让编译器知道它可以使用哪些属性和方法。

您可以传递 table 标签并将其用于创建 TableQuery ,如果您的 table class 外观定义为:

case class Events(....)

class EventsTable(tag: Tag)
  extends Table[Sample](tag, "sample_table") {
    .....
} 

你可以这样实现:

import slick.driver.H2Driver.api._
import scala.slick.driver.H2Driver.simple.Tag
import scala.concurrent.Await
import scala.concurrent.duration.Duration

trait FixtureHelper {

  val data: Seq

  def insertFixtures[T,A <: Table[T]](tag : Tag => A ,db: Database) = {
  val table : TableQuery[A] = TableQuery(tag) // create the tableQuery from the tag
    Await.result(db.run(table.schema.create), Duration.Inf)
    Await.result(db.run(table ++= data.toIterable), Duration.Inf).get // ++= accepts only Iterable[] values
  }
}

你可以像

一样使用它
object EventFixtures extends FixtureHelper {
  val data = Seq(...)
}

// in test code:
val tag= new EventsTable(_)
EventFixtures.insertFixtures[Events,EventsTable](tag)