Help us understand the problem. What is going on with this article?

Slickでauto incrementの値を使う場合のやりかた

More than 5 years have passed since last update.

前提

play-slickを使用。
https://www.playframework.com/documentation/2.4.x/PlaySlick

本題

たとえば

/**
 * Created by FScoward on 2015/09/29.
 */
@Singleton
class GroupService @Inject()(groupPersistence: GroupPersistence,
                            eventPersistence: EventPersistence,
                            groupHasUserPersistence: GroupHasUserPersistence,
                             protected val dbConfigProvider: DatabaseConfigProvider) extends HasDatabaseConfigProvider[JdbcProfile] {
  def createGroup(groupName: String, event: Event)(implicit session: Session, user: User) = {
    val q = for {
          eid <- eventPersistence.save(event.toEventRow)
          gid <- groupPersistence.save(groupName, eid)
          _ <- groupHasUserPersistence.save(gid, 1L, false)
        } yield ()

    db.run(q)
  }
}

こんな感じで使いたかったとする。
単純に

@Singleton
class EventPersistenceObj extends EventPersistence

@ImplementedBy(classOf[EventPersistenceObj])
trait EventPersistence {
  def save(eventRow: EventRow)(implicit s: Session) = {
    Event += eventRow
  }
}

と書いただけでは eid には常に1が返ってきてしまう。

auto incrementされた戻りの値を使用する際には

Event += eventRow

の部分を

Event returning Event.map(_.eventId) += eventRow

と書いてやるときちんと値が帰ってくる

補足 抜粋

gen-tablesで生成したTable

Tables.scala
  /** Entity class storing rows of table Event
   *  @param eventId Database column EVENT_ID SqlType(BIGINT), AutoInc, PrimaryKey
   *  @param title Database column TITLE SqlType(VARCHAR), Length(45,true)
   *  @param artist Database column ARTIST SqlType(VARCHAR), Length(45,true), Default(None)
   *  @param location Database column LOCATION SqlType(VARCHAR), Length(45,true)
   *  @param yearMonthDate Database column YEAR_MONTH_DATE SqlType(VARCHAR), Length(8,true)
   *  @param startTime Database column START_TIME SqlType(VARCHAR), Length(4,true), Default(None)
   *  @param endTime Database column END_TIME SqlType(VARCHAR), Length(4,true), Default(None) */
  case class EventRow(eventId: Long, title: String, artist: Option[String] = None, location: String, yearMonthDate: String, startTime: Option[String] = None, endTime: Option[String] = None)
  /** GetResult implicit for fetching EventRow objects using plain SQL queries */
  implicit def GetResultEventRow(implicit e0: GR[Long], e1: GR[String], e2: GR[Option[String]]): GR[EventRow] = GR{
    prs => import prs._
    EventRow.tupled((<<[Long], <<[String], <<?[String], <<[String], <<[String], <<?[String], <<?[String]))
  }
  /** Table description of table event. Objects of this class serve as prototypes for rows in queries. */
  class Event(_tableTag: Tag) extends Table[EventRow](_tableTag, "event") {
    def * = (eventId, title, artist, location, yearMonthDate, startTime, endTime) <> (EventRow.tupled, EventRow.unapply)
    /** Maps whole row to an option. Useful for outer joins. */
    def ? = (Rep.Some(eventId), Rep.Some(title), artist, Rep.Some(location), Rep.Some(yearMonthDate), startTime, endTime).shaped.<>({r=>import r._; _1.map(_=> EventRow.tupled((_1.get, _2.get, _3, _4.get, _5.get, _6, _7)))}, (_:Any) =>  throw new Exception("Inserting into ? projection not supported."))

    /** Database column EVENT_ID SqlType(BIGINT), AutoInc, PrimaryKey */
    val eventId: Rep[Long] = column[Long]("EVENT_ID", O.AutoInc, O.PrimaryKey)
    /** Database column TITLE SqlType(VARCHAR), Length(45,true) */
    val title: Rep[String] = column[String]("TITLE", O.Length(45,varying=true))
    /** Database column ARTIST SqlType(VARCHAR), Length(45,true), Default(None) */
    val artist: Rep[Option[String]] = column[Option[String]]("ARTIST", O.Length(45,varying=true), O.Default(None))
    /** Database column LOCATION SqlType(VARCHAR), Length(45,true) */
    val location: Rep[String] = column[String]("LOCATION", O.Length(45,varying=true))
    /** Database column YEAR_MONTH_DATE SqlType(VARCHAR), Length(8,true) */
    val yearMonthDate: Rep[String] = column[String]("YEAR_MONTH_DATE", O.Length(8,varying=true))
    /** Database column START_TIME SqlType(VARCHAR), Length(4,true), Default(None) */
    val startTime: Rep[Option[String]] = column[Option[String]]("START_TIME", O.Length(4,varying=true), O.Default(None))
    /** Database column END_TIME SqlType(VARCHAR), Length(4,true), Default(None) */
    val endTime: Rep[Option[String]] = column[Option[String]]("END_TIME", O.Length(4,varying=true), O.Default(None))
  }
  /** Collection-like TableQuery object for table Event */
  lazy val Event = new TableQuery(tag => new Event(tag))

build.sbt

  "com.typesafe.slick" %% "slick" % "3.0.2",
  "com.typesafe.slick" %% "slick-codegen" % "3.0.0",
  "com.typesafe.play" %% "play-slick" % "1.0.1",
  "com.typesafe.play" %% "play-slick-evolutions" % "1.0.1",

application.conf

db.default.driver="com.mysql.jdbc.Driver"
db.default.url="jdbc:mysql://localhost:3306/xxxx?characterEncoding=UTF8"
db.default.username=root
db.default.password=""
slick.dbs.default.driver="slick.driver.MySQLDriver$"
slick.dbs.default.url="jdbc:mysql://localhost:3306/xxxx?characterEncoding=UTF8"
slick.dbs.default.username=root
slick.dbs.default.password=""
slick.dbs.default.db.driver="com.mysql.jdbc.Driver"
slick.dbs.default.db.url="jdbc:mysql://localhost:3306/xxxx?characterEncoding=UTF8"
slick.dbs.default.db.user=root

mysql {
  dataSourceClass = "slick.jdbc.DatabaseUrlDataSource"
  properties = {
    driver=com.mysql.jdbc.Driver
    url="jdbc:mysql://localhost:3306/xxxx"
    user="root"
    password=""
  }
  numThreads = 10
}
FScoward
i love sphere !!! http://www.planet-sphere.jp/main.php 元海岸沿いのSIer/現オフィス内に海岸のある某社 https://github.com/FScoward
http://fscoward.hateblo.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away