2017-05-25 1 views
1

J'essaie de créer un modèle pour un membre TableQuery, mais les types dépendants du chemin me gâchent. J'ai une table produit de code typique comme ceci:Comment faire pour passer TableQuery en tant que générique, puis l'utiliser?

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

Alors je tente de créer une classe qui prendra une TableQuery (dans le modèle multi-db typique) comme ceci:

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

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

Ensuite, je veux l'utiliser comme ceci:

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

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

Seulement je reçois des erreurs:

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]) 

puis celui-ci:

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]) 

Qu'est-ce que je fais mal?

Répondre

3

Le code ci-dessous se compile sans problème. La méthode InsertionTemplate n'a pas pu déduire le type de E fournissant explicitement le paramètre de type a résolu le problème. il pourrait également y avoir des problèmes potentiels avec vos portées importées. assurez-vous d'avoir la déclaration d'importation import driver.api._ comme indiqué ci-dessous.

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")) 
    } 
    } 
+0

Merci rouge-un! Une idée de comment le faire si vous ne pouvez pas mettre TablesContainer et InsertionTemplate dans le même trait parent? Je ne peux pas vraiment le faire parce que Slick le génère via le Codegen (techniquement, je pourrais étendre le Codegen mais c'est un plus gros mal de tête ...). Cela est particulièrement problématique car Slick utilise slick.driver.JdbcProfile dans la classe TablesContainer et je souhaite utiliser RelationalProfile pour pouvoir effectuer des tests en mémoire. – ChoppyTheLumberjack

+0

@ChoppyTheLumberjack nous pouvons diviser le trait en deux traits différents si cela vous aide. J'ai mis à jour la réponse. En ce qui concerne l'utilisation de RelationalProfile, vous pouvez utiliser JDBCProfile et effectuer des tests en mémoire. J'utilise la base de données H2 pour cela. –

+0

Merci encore @ rogue-one. Donc, il semble que la seule façon de résoudre ce problème est de coller sur une couche au-dessus de la chose qui contient TablesContainer. Est-ce exact? – ChoppyTheLumberjack