播放Scala&;第三,得到;第xx列不能为空";在带有“的列中出错”;非空默认当前“U时间戳”;

播放Scala&;第三,得到;第xx列不能为空";在带有“的列中出错”;非空默认当前“U时间戳”;,scala,playframework,slick,slick-3.0,Scala,Playframework,Slick,Slick 3.0,我正在使用Play Framework 2.6和slick 3.2.1创建一个web应用程序。 当我尝试将一条记录插入到表“USER”中时,该表创建了带有“notnull DEFAULT CURRENT\u TIMESTAMP”的列(我使用的是MySQL),数据库抛出一个错误“column'created\u at'cannot NULL” 我知道slick生成的SQL是错误的。该语句试图将null插入到已创建的_at列中。让slick生成不包含created_at列的SQL的正确方法是什么 s

我正在使用Play Framework 2.6和slick 3.2.1创建一个web应用程序。 当我尝试将一条记录插入到表“USER”中时,该表创建了带有“notnull DEFAULT CURRENT\u TIMESTAMP”的列(我使用的是MySQL),数据库抛出一个错误“column'created\u at'cannot NULL”

我知道slick生成的SQL是错误的。该语句试图将null插入到已创建的_at列中。让slick生成不包含created_at列的SQL的正确方法是什么

scala代码摘录。

import org.joda.time.DateTime

case class User(
    id: Option[Long],
    accountId: Long,
    name: String,
    description: Option[String] = None,
    createdAt: Option[DateTime: = None,
)

class UserTable(tag: Tag) extends Table[User](tag, "user") {
  def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
  def accountId = column[Long]("account_id")
  def name = column[String]("name")
  def description = column[Option[String]]("description")
  def createdAt = column[Option[DateTime]]("created_at")
  def * = (id.?, accountId, name, description, createdAt) <> (User.tupled, User.unapply)
}

object Users extends TableQuery(new UserTable(_)) {
}

val user = User(None, accountId, name, description)
val insert = for {
  newId <- (Users returning Users.map(_.id)) += user
} yield newId

db.run(insert)

重新思考你的例子。您的表不接受
null
作为在创建的
列的值。但您的域模型允许此字段可以是
None
,它不能在数据库中以
null
以外的任何方式表示。因此,如果您希望slick生成正确的查询,您必须将在
处创建的
的类型更改为
DateTime

createdAt
不能是
选项
,您可以将
日期时间放在那里。现在
可以避免使用
选项
。还需要
DateTime
列映射器:

import slick.lifted.MappedTypeMapper
import java.sql.Date
import org.joda.time.DateTime
import slick.lifted.TypeMapper.DateTypeMapper

object DateTimeMapper {
  implicit def date2dt = MappedTypeMapper.base[DateTime, Date] (
    dt => new Date(dt.getMillis),
    date => new DateTime(date)
  )
}
或者您很可能需要它作为
时间戳
,而不是
日期

 implicit def dateTime  =
      MappedColumnType.base[DateTime, Timestamp](
        dt => new Timestamp(dt.getMillis),
        ts => new DateTime(ts.getTime)
  )
如果您不想处理
DateTime.now
,您可以这样做:

def created = column[DateTime]("createdAt", SqlType("timestamp not null default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP"))
其他信息如下:

如果你看你的投影,你必须抬起在
创建的
,就像抬起你的id一样

所以你的预测会变成:

def*=(id.?,accountId,name,description,createdAt.?)(User.tuple,User.unapply)


注意createdAt之后的

我找到了两种解决这个问题的方法(使用Slick 3.2.3)。幸运的是,对于我的用例,我没有使用Slick创建表或生成表类,因此我并不真正关心它将生成的模式是否有效

假设我们有一个简单的用户模型/表:

case class User(id: Long, name: String, createdAt: Timestamp, updatedAt: Timestamp)

class UsersDAO(tag: Tag) extends Table[User](tag, "users") {
  def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
  def name = column[String]("name")
  def createdAt = column[Timestamp]("created_at", O.AutoInc)
  def updatedAt = column[Timestamp]("updated_at", O.AutoInc)

  override def * = (id, name, createdAt, updatedAt) <>
    (User.tupled, User.unapply)
}
选项2:将字段标记为
O.AutoInc

如果使用
O.AutoInc
标记
createdAt
updatedAt
列(如上所述),只需使用
+=
语法即可:

object UsersDAO extends TableQuery(new UsersDAO(_)) {
  def create(u: User) = this returning this.map(_.id) += user
}
目前似乎有几个问题与此相关。希望一旦他们解决了,会有更好的办法。

这样,您的意思是我必须编写
User(None,accountId,name,description,new DateTime())
来创建要插入的用户实例,并且表上的修饰符
DEFAULT CURRENT_TIMESTAMP
永远不会与slick一起使用吗?在您的情况下,是的,它不会被使用。是否有可能以你想要的方式实施,我现在还不知道。考虑一下:在表定义中可以实现默认值,但我不确定。
object UsersDAO extends TableQuery(new UsersDAO(_)) {
  def create(u: User) = this map { c =>
    (c.name) // only include columns you want to send
  } returning this.map(_.id) += (u.name)
}
object UsersDAO extends TableQuery(new UsersDAO(_)) {
  def create(u: User) = this returning this.map(_.id) += user
}