[SlickException:读取列的 NULL 值 (USERS /670412212).LOGIN_ID]

问题描述 投票:0回答:5

我正在使用 Slick 1.0.0 和 play Framework 2.1.0。当我查询我的

Users
表时,出现以下错误。 DB 中
LOGIN_ID
的值为空。 我正在执行的查询是:

    val user = { for { u <- Users if u.providerId === id.id } yield u}.first

这会导致以下错误:

play.api.Application$$anon$1: Execution exception[[SlickException: Read NULL value for column (USERS /670412212).LOGIN_ID]]
    at play.api.Application$class.handleError(Application.scala:289) ~[play_2.10.jar:2.1.0]
    at play.api.DefaultApplication.handleError(Application.scala:383) [play_2.10.jar:2.1.0]
    at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$12$$anonfun$apply$24.apply(PlayDefaultUpstreamHandler.scala:314) [play_2.10.jar:2.1.0]
    at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$12$$anonfun$apply$24.apply(PlayDefaultUpstreamHandler.scala:312) [play_2.10.jar:2.1.0]
    at play.api.libs.concurrent.PlayPromise$$anonfun$extend1$1.apply(Promise.scala:113) [play_2.10.jar:2.1.0]
    at play.api.libs.concurrent.PlayPromise$$anonfun$extend1$1.apply(Promise.scala:113) [play_2.10.jar:2.1.0]
scala.slick.SlickException: Read NULL value for column (USERS /670412212).LOGIN_ID
    at scala.slick.lifted.Column$$anonfun$getResult$1.apply(ColumnBase.scala:29) ~[slick_2.10-1.0.0.jar:1.0.0]
    at scala.slick.lifted.TypeMapperDelegate$class.nextValueOrElse(TypeMapper.scala:158) ~[slick_2.10-1.0.0.jar:1.0.0]
    at scala.slick.driver.BasicTypeMapperDelegatesComponent$TypeMapperDelegates$StringTypeMapperDelegate.nextValueOrElse(BasicTypeMapperDelegatesComponent.scala:146) ~[slick_2.10-1.0.0.jar:1.0.0]
    at scala.slick.lifted.Column.getResult(ColumnBase.scala:28) ~[slick_2.10-1.0.0.jar:1.0.0]
    at scala.slick.lifted.Projection15.getResult(Projection.scala:627) ~[slick_2.10-1.0.0.jar:1.0.0]
    at scala.slick.lifted.Projection15.getResult(Projection.scala:604) ~[slick_2.10-1.0.0.jar:1.0.0]

我的用户表定义为:

package models

import scala.slick.driver.MySQLDriver.simple._

case class User(userId:String,email:String,loginId:String,fullName:String,firstName:String,lastName:String,location:String,homeTown:String,providerId:String,provider:String,state:String,zip:String,accessKey:String,refreshKey:String,avatarUrl:String)

object Users extends Table[User]("USERS") {
  def userId = column[String]("USER_ID", O.PrimaryKey) // This is the primary key column
  def email =  column[String]("EMAIL",O.NotNull)
  def loginId = column[String]("LOGIN_ID",O.Nullable)
  def fullName = column[String]("FULL_NAME",O.NotNull)
  def firstName = column[String]("FIRST_NAME",O.Nullable)
  def lastName = column[String]("LAST_NAME",O.Nullable)
  def location = column[String]("LOCATION",O.Nullable)
  def homeTown = column[String]("HOME_TOWN",O.Nullable)
  def providerId = column[String]("PROVIDER_ID",O.Nullable)
  def provider = column[String]("PROVIDER",O.Nullable)
  def state = column[String]("STATE",O.Nullable)
  def zip = column[String]("ZIP",O.Nullable)
  def accessKey = column[String]("ACCESS_KEY",O.Nullable)
  def refreshKey = column[String]("REFRESH_KEY",O.Nullable)
  def avatarUrl = column[String]("AVATAR_URL",O.Nullable)

  // Every table needs a * projection with the same type as the table's type parameter
  def * = userId ~ email ~ loginId ~ fullName ~ firstName ~ lastName ~ location ~ homeTown ~ providerId ~ provider ~ state ~ zip ~ accessKey ~ refreshKey ~ avatarUrl <> (User,User.unapply _)
}

请帮忙。看起来 Slick 无法处理 DB 中的 Null 值?

scala playframework-2.0 slick typesafe-stack
5个回答
31
投票

您的案例类别不合适。如果您使用

O.Nullable
,则您的所有属性都必须是
Option[String]


7
投票

如果出现此错误,您必须将属性设为

O.Nullable
,您必须指定查询返回一个选项。

例如,假设您执行了

rightJoin
,您可能不希望将正确记录的属性设置为可选。在这种情况下,您可以使用
.?

自定义生成结果的方式
val results = (for {
  (left, right) <- rightRecord.table rightJoin leftRecord.table on (_.xId === _.id)
  } yield (rightRecord.id, leftRecord.name.?)).list
results map (r => SomeJoinedRecord(Some(r._1), r._2.getOrElse(default)))

4
投票

如果列包含空值并且在运行时它在列响应中获得空值,则会出现此问题。如果您在下面的代码中看到,我的 cust_id 可以为空,但它没有空值。因为,有一项工作可以确保 is 永远不为空。因此,下面的映射有效。但是,最佳实践是查看表结构并相应地创建类。这可以避免令人讨厌的运行时异常。

如果数据库上的表定义如下:

CREATE TABLE public.perf_test (
    dwh_id serial NOT NULL,
    cust_id int4 NULL,
    cust_address varchar(30) NULL,
    partner_id int4 NULL,
    CONSTRAINT perf_test_new_dwh_id_key UNIQUE (dwh_id)
);

对应的类定义可以如下。但是,建议将 cust_id 也设置为

Option[Int]
。但是,只要它有值且没有空值,就不会遇到错误。

导入 slick.jdbc.PostgresProfile.api._

class PerfTest(tag: Tag) extends Table[(Int, Int, Option[String], Option[Int])](tag, "perf_test") {
  def dwhId = column[Int]("dwh_id")
  def custId = column[Int]("cust_id")
  def custAddress = column[Option[String]]("cust_address")
  def partnerId = column[Option[Int]]("partner_id")
  def * = (dwhId, custId, custAddress,partnerId)
}

0
投票

我遇到的情况是,数据库中出现异常,并且某些值意外为空 - 那些我没想到的值。所以不要忘记检查您的数据:)


0
投票

基于@ForeverLearner的答案,我发现当你有一个用自定义列映射器表示为

nullable
Option[Foo]
字段时,也会出现这种情况;说将类转换为 JSON 字段。

如果映射器返回

MappedColumnType.base[Option[Foo], String]
例如

    MappedColumnType.base[Optionp[Foo], String](
      maybeFoo => maybeFoo.map(Json.toJson(_).toString()).getOrElse("{}"),
      json => Try(Json.parse(json).as[Foo]).toOption
    )

如果列包含空值,您将得到异常。解决办法有两种:

  1. 在列中使用默认值,例如上面的 JSON
    {}
  2. 不要尝试在映射器中将值转换为
    Option[Foo]
    ;相反,请勿在列中使用
    Option[Foo]
    并确保在构建案例类时使用
    .?
© www.soinside.com 2019 - 2024. All rights reserved.