【问题标题】:Slick: How does autoInc work in the MultiDBCakeExample example?Slick:autoInc 在 MultiDBCakeExample 示例中是如何工作的?
【发布时间】:2012-12-06 07:53:23
【问题描述】:

我正在尝试了解 Slick 的工作原理以及如何使用它...查看他们在 GitHub 中的示例,我最终在MultiDBCakeExample.scala 中得到了这段代码 sn-p:

trait PictureComponent { this: Profile => //requires a Profile to be mixed in...
  import profile.simple._ //...to be able import profile.simple._

  object Pictures extends Table[(String, Option[Int])]("PICTURES") {
    ...

    def * = url ~ id

    val autoInc = url returning id into { case (url, id) => Picture(url, id) }

    def insert(picture: Picture)(implicit session: Session): Picture = {
      autoInc.insert(picture.url)
    }
  }
}

我想* 方法会在表中返回一行,而autoInc 应该以某种方式提供自动递增实体 ID 的功能......但老实说,我在理解这段代码时遇到了一些麻烦。 returning 指的是什么? autoInc 返回什么?

我查看了 Slick 文档,但找不到有用的信息。任何帮助将不胜感激;-)

【问题讨论】:

    标签: scala slick


    【解决方案1】:

    因为autoInc 可能会造成混淆,我将为您提供一个工作示例(请注意,我的数据库是 PostgreSQL,所以我需要使用forInsert 进行破解,以使 Postgresql 驱动程序增加 auto-inc 值)。

    case class GeoLocation(id: Option[Int], latitude: Double, longitude: Double, altitude: Double)
    
    /**
     * Define table "geo_location".
     */
    object GeoLocations extends RichTable[GeoLocation]("geo_location") {
      def latitude = column[Double]("latitude")
      def longitude = column[Double]("longitude")
      def altitude = column[Double]("altitude")
    
      def * = id.? ~ latitude ~ longitude ~ altitude <> (GeoLocation, GeoLocation.unapply _)
      def forInsert = latitude ~ longitude ~ altitude <> ({ (lat, long, alt) => GeoLocation(None, lat, long, alt) },
        { g: GeoLocation => Some((g.latitude, g.longitude, g.altitude)) })
    }
    

    我的 RichTable 是一个抽象类,以便不为我拥有的每个表声明 id,而只是扩展它:

    abstract class RichTable[T](name: String) extends Table[T](name) {
      def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
    
      val byId = createFinderBy(_.id)
    
    }
    

    并像这样使用它:

    GeoLocations.forInsert.insert(GeoLocation(None, 22.23, 25.36, 22.22))
    

    由于您将None 传递给id,所以当Slick 插入这个新实体时,它将由PostgreSql 驱动程序自动生成。 我开始使用 Slick 已经有几个星期了,我真的推荐它!

    更新:如果您不想使用forInsert 投影,另一种方法如下 - 在我的情况下,实体是Address

    在创建模式时为每个表创建序列:

    session.withTransaction {
      DBSchema.tables.drop
      DBSchema.tables.create
      // Create schemas to generate ids too.
      Q.updateNA("create sequence address_seq")
    }
    

    定义一个使用序列生成 id 的方法(我在 RichTable 类中定义了这个 once

      def getNextId(seqName: String) = Database { implicit db: Session =>
        Some((Q[Int] + "select nextval('" + seqName + "_seq') ").first)
      }
    

    并在映射器中覆盖 insert 方法,如:

      def insert(model : Address) = Database { implicit db: Session =>
        *.insert(model.copy(id = getNextId(classOf[Address].getSimpleName())))
      }
    

    现在,您可以在执行插入操作时传递 None,这些方法会为您提供很好的工作...

    【讨论】:

    • ... 如果我不想要一个自动递增的 ID 怎么办?例如,我可以通过对电子邮件地址进行哈希处理来生成实体 ID……您的示例是否适用于 auto-inc 和自定义 ID?
    • 是的,不是传递None,而是传递您的实际ID,例如GeoLocations.forInsert.insert(GeoLocation(Some(134), 22.23, 25.36, 22.22))
    • 表变大了怎么办?也许 15-20 列...forInsert 方法变成了怪物!
    • @alexBrand 在 Slick 2.x 中,不再需要 forInsert
    猜你喜欢
    • 2011-02-06
    • 2013-10-12
    • 1970-01-01
    • 1970-01-01
    • 2015-07-22
    • 2020-03-20
    • 2017-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多