【问题标题】:Slick, H2 insert query auto increment IDSlick,H2 插入查询自动增量 ID
【发布时间】:2014-08-03 22:03:56
【问题描述】:

我在 H2 有这张桌子:

CREATE TABLE computer (id BIGINT NOT NULL, name VARCHAR(255) NOT NULL, introduced TIMESTAMP, discontinued TIMESTAMP, company_id BIGINT, CONSTRAINT pk_computer PRIMARY KEY (id));
CREATE SEQUENCE computer_seq START WITH 1000;

为它自动生成的类:

  case class ComputerRow(id: Long, name: String, introduced: Option[java.sql.Timestamp], discontinued: Option[java.sql.Timestamp], companyId: Option[Long])
  /** GetResult implicit for fetching ComputerRow objects using plain SQL queries */
  implicit def GetResultComputerRow(implicit e0: GR[Long], e1: GR[String], e2: GR[Option[java.sql.Timestamp]], e3: GR[Option[Long]]): GR[ComputerRow] = GR{
    prs => import prs._
    ComputerRow.tupled((<<[Long], <<[String], <<?[java.sql.Timestamp], <<?[java.sql.Timestamp], <<?[Long]))
  }
  /** Table description of table COMPUTER. Objects of this class serve as prototypes for rows in queries. */
  class Computer(tag: Tag) extends Table[ComputerRow](tag, "COMPUTER") {
    def * = (id, name, introduced, discontinued, companyId) <> (ComputerRow.tupled, ComputerRow.unapply)
    /** Maps whole row to an option. Useful for outer joins. */
    def ? = (id.?, name.?, introduced, discontinued, companyId).shaped.<>({r=>import r._; _1.map(_=> ComputerRow.tupled((_1.get, _2.get, _3, _4, _5)))}, (_:Any) =>  throw new Exception("Inserting into ? projection not supported."))

    /** Database column ID PrimaryKey */
    val id: Column[Long] = column[Long]("ID", O.PrimaryKey)
    /** Database column NAME  */
    val name: Column[String] = column[String]("NAME")
    /** Database column INTRODUCED  */
    val introduced: Column[Option[java.sql.Timestamp]] = column[Option[java.sql.Timestamp]]("INTRODUCED")
    /** Database column DISCONTINUED  */
    val discontinued: Column[Option[java.sql.Timestamp]] = column[Option[java.sql.Timestamp]]("DISCONTINUED")
    /** Database column COMPANY_ID  */
    val companyId: Column[Option[Long]] = column[Option[Long]]("COMPANY_ID")

    /** Foreign key referencing Company (database name FK_COMPUTER_COMPANY_1) */
    lazy val companyFk = foreignKey("FK_COMPUTER_COMPANY_1", companyId, Company)(r => r.id, onUpdate=ForeignKeyAction.Restrict, onDelete=ForeignKeyAction.Restrict)
  }
  /** Collection-like TableQuery object for table Computer */
  lazy val Computer = new TableQuery(tag => new Computer(tag))

但是,我似乎无法插入新行。下面的尝试

val row = ("name", new Timestamp((new Date).getTime), new Timestamp((new Date).getTime), 123)

DB.withDynSession {
    Computer.map( r =>
        (r.name, r.introduced, r.discontinued, r.companyId)
    ) += row
}

抛出错误

[JdbcSQLException: NULL not allowed for column "ID"; SQL statement: INSERT INTO "COMPUTER" ("NAME","INTRODUCED","DISCONTINUED","COMPANY_ID") VALUES (?,?,?,?) [23502-175]]

同样的方法适用于 MySQL 和 PostgreSQL,所以我猜 H2 没有相同的主 ID 自动递增功能?那么如何让我的插入与 slick 一起使用呢?

这是使用 Anorm 的同一张表的工作示例:

DB.withConnection { implicit connection =>
    SQL(
        """
            insert into computer values (
                (select next value for computer_seq), 
                {name}, {introduced}, {discontinued}, {company_id}
            )
        """
    ).on(
        'name -> "name",
        'introduced -> new Timestamp((new Date).getTime),
        'discontinued -> new Timestamp((new Date).getTime),
        'company_id -> 123
    ).executeUpdate()
}

【问题讨论】:

    标签: scala h2 slick anorm slick-2.0


    【解决方案1】:

    尝试为案例类赋予 id 的默认值,如下所示:

    case class ComputerRow(id: Long = 0, name: String, introduced: Option[java.sql.Timestamp], discontinued: Option[java.sql.Timestamp], companyId: Option[Long])
    

    我不确定H2,但是当我使用Postgres 时,我通常会指定id 字段的默认值以符合Slick 的最终检查,然后在数据库端插入的值是由序列自动处理。

    编辑:

    我可能错了,但我注意到您创建了一个序列而不分配它:

    CREATE TABLE computer (id BIGINT NOT NULL, name VARCHAR(255) NOT NULL, introduced TIMESTAMP, discontinued TIMESTAMP, company_id BIGINT, CONSTRAINT pk_computer PRIMARY KEY (id));
    CREATE SEQUENCE computer_seq START WITH 1000;
    

    Postgres 中创建序列,然后像这样分配它们:

    create table users (
      id  bigint not null
    );
    
    create sequence users_seq;
    alter table users alter column id set default nextval('users_seq');
    

    H2 中,据我所知,这是您分配自动增量的方式:

    create table test(id bigint auto_increment, name varchar(255));
    

    取自this SO question

    【讨论】:

    • 我不想碰它,因为它是由 Slick 自动生成的。当然,应该有更一致的方式来做到这一点。
    • 我添加了一些可能相关的内容。
    • 创建查询不是我写的,取自这个示例:github.com/playframework/playframework/tree/master/samples/…
    • 另一件事是,如果一列具有自动递增功能,则 slick 代码生成器会在字段中添加 O.AutoInc,您的 id 列至少在 Postgres 中应该看起来像 val id: Column[Long] = column[Long]("ID", O.PrimaryKey, O.AutoInc),不幸的是我没有H2 用户,我无法进一步帮助您,如果 autoinc 使用普通 SQL 工作,您可能可以尝试,例如进行一些插入。此外,要插入的 sql 语句具有 (select next value for computer_seq),它手动选择序列中的下一个值并将其用作 id。
    【解决方案2】:

    据我所知,这不是 Slick 问题,但您的 DDL 语句没有指定 H2 的自动增量。查看示例项目的 play-slick SQL 代码:https://github.com/playframework/play-slick/blob/master/samples/computer-database/conf/evolutions/default/1.sql

    同时查看 H2 文档:http://www.h2database.com/html/grammar.html#column_definition

    【讨论】:

      猜你喜欢
      • 2018-02-17
      • 2016-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-05
      • 1970-01-01
      • 2012-03-10
      • 2016-04-06
      相关资源
      最近更新 更多