我一直在寻找如何为公共CRUD和其他类型的操作实现通用特性,我查看了
this和
this,并且指定的方法运行良好.
我想要的是一个通用的插入方法,我的类目前看起来像这样(非泛型实现):
object CampaignModel { val campaigns = TableQuery[Campaign] def insert(campaign: CampaignRow)(implicit s: Session) = { campaigns.insert(campaign) } }
到目前为止,我在第一个链接之后尝试了这个(通用实现):
trait PostgresGeneric[T <: Table[A],A] { val tableReference = TableQuery[T] def insertGeneric(row: ? What type goes here ?)(implicit s: Session) = tableReference.insert(row) }
当我检查insert方法时,看起来正确的类型应该是T#TableElementType但是我的知识非常基础而且我无法绕过类型,我尝试了T和A并且编译器说classtype不符合特质一个人.
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") }
我设法让它工作,这是我的通用特性:
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 } }
其中RichTable是一个带有id字段的抽象类,这个带有上限约束对于获取T#TableElementType的id字段很有用(有关更多信息,请参阅this):
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) }
我的广告系列表现在看起来像这样:
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,CampaignRow.unapply) def ? = (id.?,(_: Any) => throw new Exception("Inserting into ? projection not supported.")) override val id: Column[Long] = column[Long]("id",O.PrimaryKey) val name: Column[Option[String]] = column[Option[String]]("name") }
实现通用特征的模型如下所示:
object CampaignModel extends PostgresGeneric[Campaign,CampaignRow] { override val tableReference: PostgresDriver.simple.TableQuery[Tables.Campaign] = TableQuery[Campaign] def insertCampaign(row: CampaignRow) = { insert(CampaignRow(0,"test")) } }