【问题标题】:How to define a type that is subject to several implicit conversions?如何定义受多个隐式转换影响的类型?
【发布时间】:2015-06-02 10:38:32
【问题描述】:

我正在使用 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,则找不到此属性。

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

那么我怎样才能一般地输入table 以便编译这个特征并且可以找到所有这些隐式添加的成员?

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

【问题讨论】:

    标签: scala slick


    【解决方案1】:

    您可以传递 tableTag 并将其用于创建 TableQuery ,如果您的表类看起来定义为:

    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) 
    

    【讨论】:

    • 感谢您的回复,但您是怎么知道的?我的意思是,通过查看所有隐式转换,你怎么知道你需要使用哪种类型?
    • 对不起,我听不懂。代码 sn-p 怎么样,它有效吗?
    • 我还没有机会尝试。但我想知道你是怎么知道要做什么的。类型是隐式转换的,那么你是怎么知道使用哪种类型的呢?
    • 任何表的tableQuery(在您的代码EventsTable中)类通常生成为:val table : TableQuery[EventsTable] = TableQuery(new EventsTable(_))
    • A tableQuery 用于任何表类(在您的代码 EventsTable 中),通常由以下语句生成:val table : TableQuery[EventsTable] = TableQuery(new EventsTable(_)).. tag i传递给通用特征的是new Events(_),并且您可以看到这个标签特定于每个表,因此特征中的TableQuey(tag) 语句为每个表生成特定的表查询。希望我回答了你的观点。
    猜你喜欢
    • 1970-01-01
    • 2011-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-27
    • 2012-10-02
    • 2014-10-21
    相关资源
    最近更新 更多