2014-04-28 6 views
6

Ich habe mich gefragt, wie man ein generisches Merkmal für commons CRUD und andere Arten von Operationen implementieren, sah ich this und this und die angegebene Methode funktioniert gut.Slick 2.0 Generic CRUD-Operationen

Was würde ich eine generische Methode haben, wie zum Einfügen, sieht meine Klasse wie folgt zur Zeit (nicht generische Implementierung):

object CampaignModel { 
    val campaigns = TableQuery[Campaign] 

    def insert(campaign: CampaignRow)(implicit s: Session) = { 
    campaigns.insert(campaign) 
    } 
} 

Was ich bisher versucht, den ersten Link folgen, war diese (generische Implementierung):

trait PostgresGeneric[T <: Table[A], A] { 
    val tableReference = TableQuery[T] 

    def insertGeneric(row: ? What type goes here ?)(implicit s: Session) = tableReference.insert(row) 

} 

Wenn ich die insert Methode sieht es aus wie die richtige Art inspizieren sollte T#TableElementType aber meines Wissens sein ist ziemlich einfach und ich kann meinen Kopf um Arten nicht wickeln, habe ich versucht, T und A und der Compiler sagt, dass der Classtyp nicht dem Charakter des eigenen entspricht.

Weitere Infos, werden die Tabellen mit den Slick-Tisch-Generierungs-Tool erzeugt

case class CampaignRow(id: Long, name: Option[String]) 

/** Table description of table campaign. Objects of this class serve as prototypes for rows in queries. */ 
class Campaign(tag: Tag) extends Table[CampaignRow](tag, "campaign") { 
    def * = (id, name) <>(CampaignRow.tupled, CampaignRow.unapply) 

    /** Maps whole row to an option. Useful for outer joins. */ 
    def ? = (id.?, name).shaped.<>({ 
    r => import r._; _1.map(_ => CampaignRow.tupled((_1.get, _2))) 
    }, (_: Any) => throw new Exception("Inserting into ? projection not supported.")) 

    /** Database column id AutoInc, PrimaryKey */ 
    val id: Column[Long] = column[Long]("id", O.AutoInc, O.PrimaryKey) 
    /** Database column name */ 
    val name: Column[Option[String]] = column[Option[String]]("name") 
} 

Antwort

11

ich es geschaffen, damit es funktioniert, das ist mein generisches Merkmal:

import scala.slick.driver.PostgresDriver 
import scala.slick.driver.PostgresDriver.simple._ 
import path.to.RichTable 

trait PostgresGeneric[T <: RichTable[A], A] { 

    val tableReference: TableQuery[T] 

    def insert(row: T#TableElementType)(implicit s: Session) = 
    tableReference.insert(row) 

    def insertAndGetId(row: T#TableElementType)(implicit s: Session) = 
    (tableReference returning tableReference.map(_.id)) += row 

    def deleteById(id: Long)(implicit s: Session): Boolean = 
    tableReference.filter(_.id === id).delete == 1 

    def updateById(id: Long, row: T#TableElementType)(implicit s: Session): Boolean = 
    tableReference.filter(_.id === id).update(row) == 1 

    def selectById(id: Long)(implicit s: Session): Option[T#TableElementType] = 
    tableReference.filter(_.id === id).firstOption 

    def existsById(id: Long)(implicit s: Session): Boolean = { 
    (for { 
     row <- tableReference 
     if row.id === id 
    } yield row).firstOption.isDefined 
    } 
} 

Wo RichTable eine abstrakte Klasse ist mit einem ID-Feld ist dies, mit der Obergrenze Einschränkung nützlich, um das ID-Feld von T#TableElementType (siehe this für weitere Informationen):

import scala.slick.driver.PostgresDriver.simple._ 
import scala.slick.jdbc.{GetResult => GR} 

abstract class RichTable[T](tag: Tag, name: String) extends Table[T](tag, name) { 
    val id: Column[Long] = column[Long]("id", O.PrimaryKey, O.AutoInc) 
} 

Und meine Kampagne Tabelle sieht nun wie folgt aus:

import scala.slick.driver.PostgresDriver.simple._ 
import scala.slick.jdbc.{GetResult => GR} 
import scala.slick.lifted.TableQuery 

case class CampaignRow(id: Long, name: Option[String]) 

class Campaign(tag: Tag) extends RichTable[CampaignRow](tag, "campaign") { 
    def * = (id, name) <>(CampaignRow.tupled, CampaignRow.unapply) 

    def ? = (id.?, name).shaped.<>({ 
    r => import r._; _1.map(_ => CampaignRow.tupled((_1.get, _2))) 
    }, (_: Any) => throw new Exception("Inserting into ? projection not supported.")) 

    override val id: Column[Long] = column[Long]("id", O.AutoInc, O.PrimaryKey) 
    val name: Column[Option[String]] = column[Option[String]]("name") 
} 

Das Modell die allgemeine Eigenschaft wie folgt aussieht Umsetzung:

object CampaignModel extends PostgresGeneric[Campaign, CampaignRow] { 

    override val tableReference: PostgresDriver.simple.TableQuery[Tables.Campaign] = 
    TableQuery[Campaign] 

    def insertCampaign(row: CampaignRow) = { 
    insert(CampaignRow(0, "test")) 
    } 
}