3
votes

In my Play + Slick 3.2.1 (using PlaySlick 3.0.0) project, I'm trying to have a nullable column password_id on a table user:

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)
}

Table creation in evolutions script:

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)
);

Now, when I'm trying to insert a new user into that table as follows

def dbConfig = DatabaseConfigProvider.get[JdbcProfile](Play.current)
dbConfig.db.run(users += User(0, "test", None))

I run into an exception:

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)
...

To me, this indicates that Slick still interprets password_id as non-nullable.

Am I missing something in my config, or might this be a bug?

(For what it's worth, I couldn't find any example/seed project for Slick 3.x using nullable columns at all.)


Update: Mystery solved

After further investigation it turns out I've been looking in the wrong place.

There was a different table with a property not declared as nullable (i.e. Option[...]) that unexpectedly was fed a null value. Because of the async nature of DB operations and the fact those two happened almost at the same time, I was wrongly led to above assumptions when debugging. To be fair, that error stack trace wasn't too helpful either.

I'll just leave this question for posteriority, so people investating similar issues can learn from my mistakes.

1

1 Answers

0
votes

Can you change your column shape from:

 override def * = (id, name, passwordId) <> (User.tupled, User.unapply)

to:

 override def * = (id, name, passwordId.?) <> (User.tupled, User.unapply)

Additionally, remove the option[Long] from the passwordId def to just Long?