如何将TableQuery作为Generic传递然后使用它?

时间:2017-05-25 16:00:29

标签: scala generics slick

我试图模板化一个TableQuery成员,但路径依赖类型让我搞砸了。我有一个典型的代码生成表,如下所示:

trait TablesContainer {
    case class MembersRow(firstName:String, lastName:String)

    class Members(_tableTag: Tag) extends Table[MembersRow](_tableTag, Some("dbo"), "MEMBERS") {
        def * = (firstName, lastName) <> (MembersRow.tupled, MembersRow.unapply)

        val firstName: Rep[String] = column[String]("FIRM_NAME")
        val lastName: Rep[String] = column[String]("LAST_NAME")
    }
}

然后我尝试创建一个将采用TableQuery(在典型的multi-db模式中)的类,如下所示:

class TemplateHolder(profile: RelationalProfile) {
    import profile.api._

    class InsertionTemplate[T <: Table[E], E](tableQuery: TableQuery[T]) {
        def apply(insertRow:E) = {
          tableQuery += insertRow
        }
    }
}

然后我想这样使用它:

def template = new InsertionTemplate(TableQuery[TablesContainer.Members])

template.apply(MembersRow("Joe", "Bloggs"))

只有我收到错误:

Error:(134, 28) inferred type arguments [com.test.TablesContainer.Members,Nothing] do not conform to class InsertionTemplate's type parameter bounds [T <: RelationalProfileConstants.this.profile.api.Table[E],E]
  def template = new InsertionTemplate(TableQuery[TablesContainer.Members])

然后这一个:

Error:(134, 60) type mismatch;
 found   : slick.lifted.TableQuery[com.test.TablesContainer.Members]
 required: RelationalProfileConstants.this.profile.api.TableQuery[T]
    (which expands to)  slick.lifted.TableQuery[T]
  def template = new InsertionTemplate(TableQuery[TablesContainer.Members])

我做错了什么?

1 个答案:

答案 0 :(得分:3)

以下代码编译没有问题。 InsertionTemplate方法无法推断E的类型,因此明确提供类型参数解决了问题。导入的范围也可能存在潜在问题。确保您拥有导入语句import driver.api._,如下所示。

  trait Container1  {

    self: HasDatabaseConfigProvider[JdbcProfile] =>

    import driver.api._

    trait TablesContainer {
      case class MembersRow(firstName:String, lastName:String)
      class Members(_tableTag: Tag) extends Table[MembersRow](_tableTag, Some("dbo"), "MEMBERS") {
        def * = (firstName, lastName) <> (MembersRow.tupled, MembersRow.unapply)
        val firstName: Rep[String] = column[String]("FIRM_NAME")
        val lastName: Rep[String] = column[String]("LAST_NAME")
      }
    }
  }


  trait Container2 {

    self: HasDatabaseConfigProvider[JdbcProfile] with Container1 =>

    import driver.api._

    class InsertionTemplate[T <: Table[E], E](tableQuery: TableQuery[T]) {
      def apply(insertRow:E) = {
        tableQuery += insertRow
      }
    }

    class Run extends TablesContainer {
      // specify explicit type parameters.
      def template = new InsertionTemplate[Members,MembersRow](TableQuery[Members])
      template.apply(MembersRow("Joe", "Bloggs"))
    }
  }