在我的 Play + Slick 3.2.1(使用 PlaySlick 3.0.0)项目中,我试图在表 user
上有一个可为空的列 password_id
:
case class User(id: Long, name: String, passwordId: Option[Long]) extends Identity
class UserTable(tag: Tag) extends Table[User](tag, "user") {
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def name = column[String]("name", O.Unique)
def passwordId = column[Option[Long]]("password_id", O.Unique)
def password = foreignKey("password", passwordId, Passwords.passwords)(_.id)
override def * = (id, name, passwordId) <> (User.tupled, User.unapply)
}
在 evolutions 脚本中创建表:
create table user (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR NOT NULL UNIQUE,
password_id BIGINT UNIQUE,
FOREIGN KEY(password_id) REFERENCES password(id)
);
现在,当我尝试按如下方式将新用户插入该表时
def dbConfig = DatabaseConfigProvider.get[JdbcProfile](Play.current)
dbConfig.db.run(users += User(0, "test", None))
我遇到了一个异常:
slick.SlickException: Read NULL value (null) for ResultSet column <computed>
at slick.jdbc.SpecializedJdbcResultConverter$$anon$1.read(SpecializedJdbcResultConverters.scala:27)
at slick.jdbc.SpecializedJdbcResultConverter$$anon$1.read(SpecializedJdbcResultConverters.scala:24)
at slick.relational.ProductResultConverter.read(ResultConverter.scala:56)
at slick.relational.ProductResultConverter.read(ResultConverter.scala:46)
at slick.relational.TypeMappingResultConverter.read(ResultConverter.scala:136)
at slick.jdbc.JdbcInvokerComponent$QueryInvokerImpl.extractValue(JdbcInvokerComponent.scala:36)
at slick.jdbc.StatementInvoker$$anon$1.extractValue(StatementInvoker.scala:67)
at slick.jdbc.PositionedResultIterator.fetchNext(PositionedResult.scala:176)
at slick.util.ReadAheadIterator.update(ReadAheadIterator.scala:28)
at slick.util.ReadAheadIterator.hasNext(ReadAheadIterator.scala:34)
...
对我来说,这表明 Slick 仍然将 password_id
解释为不可为 null。
我的配置中是否遗漏了什么,或者这可能是一个错误?
(就其值(value)而言,我根本找不到任何使用可空列的 Slick 3.x 示例/种子项目。)
更新:谜团解开了
经过进一步调查,我发现我找错地方了。
有一个不同的表,其属性未声明为可为 null(即 Option[...]
),但意外地被提供了一个 null 值。由于数据库操作的异步性质以及这两者几乎同时发生的事实,我在调试时错误地得出了上述假设。公平地说,错误堆栈跟踪也不是很有帮助。
我只是把这个问题留作后验,所以投资类似问题的人可以从我的错误中吸取教训。
最佳答案
你能改变你的列形状吗:
override def * = (id, name, passwordId) <> (User.tupled, User.unapply)
到:
override def * = (id, name, passwordId.?) <> (User.tupled, User.unapply)
另外,从 passwordId def 中删除选项 [Long] 到 Long?
关于scala - 可空列在尝试写入空值时导致 SlickException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48437919/