【问题标题】:How do I write slick table definitions with nullable columns?如何使用可为空的列编写光滑的表定义?
【发布时间】:2017-05-07 16:49:37
【问题描述】:

这个表定义一直有效,直到我意识到具有可为空的列意味着我需要使用 Option[String] 而不仅仅是 String。这是我所做的唯一更改,这就是我的代码现在的样子。

class RespondentTableDef(tag: Tag) extends Table[Respondent](tag, "respondent") {

  def id = column[Long]("id", O.PrimaryKey)
  def uuid = column[String]("uuid")
  def version = column[Long]("version")
  def task = column[Long]("task")
  def firstName = column[Option[String]]("first_name")
  def lastName = column[Option[String]]("last_name")
  def ageGroup = column[Option[String]]("age_group")
  def incomeLevel = column[Option[String]]("income_level")
  def employmentStatus = column[Option[String]]("employment_status")
  def maritalStatus = column[Option[String]]("marital_status")
  def housingStatus = column[Option[String]]("housing_status")
  def educationStatus = column[Option[String]]("education_status")
  def gender = column[Option[String]]("gender")

  override def * =
    (id, uuid, version, task, firstName, lastName, ageGroup, incomeLevel, employmentStatus, maritalStatus, housingStatus, educationStatus, gender) <> (Respondent.tupled, Respondent.unapply)
}

编译时出现此错误。

[error] /Users/roy/adivinate/survey2/app/model/Respondent.scala:45: No matching Shape found.
[error] Slick does not know how to map the given types.
[error] Possible causes: T in Table[T] does not match your * projection. Or you use an unsupported type in a Query (e.g. scala List).
[error]   Required level: slick.lifted.FlatShapeLevel
[error]      Source type: (slick.lifted.Rep[Long], slick.lifted.Rep[String], slick.lifted.Rep[Long], slick.lifted.Rep[Long], slick.lifted.Rep[Option[String]], slick.lifted.Rep[Option[String]], slick.lifted.Rep[Option[String]], slick.lifted.Rep[Option[String]], slick.lifted.Rep[Option[String]], slick.lifted.Rep[Option[String]], slick.lifted.Rep[Option[String]], slick.lifted.Rep[Option[String]], slick.lifted.Rep[Option[String]])
[error]    Unpacked type: (Long, String, Long, Long, String, String, String, String, String, String, String, String, String)
[error]      Packed type: Any
[error]     (id, uuid, version, task, firstName, lastName, ageGroup, incomeLevel, employmentStatus, maritalStatus, housingStatus, educationStatus, gender) <> (Respondent.tupled, Respondent.unapply)
[error]                                                                                                                                                    ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 5 s, completed Dec 21, 2016 8:53:17 PM

【问题讨论】:

    标签: scala playframework slick codegen


    【解决方案1】:

    这基本上是一件简单的事情——您的案例类需要这些字段是可选的。例如。而不是(在你的案例类中):firstName: String 你应该有 firstName: Option[String]

    【讨论】:

      【解决方案2】:

      在模型类中将您的字段声明为 Option[T] 而不是 T 以使相应的列可空

      让我们通过一个例子来理解这一点

      case class Foo(name: String, rating: Option[Int])
      
      class Foos(tag: Tag) extends Table[Foo](tag, "foos") {
        def name = column[String]("name") //name is not null
        def rating = column[Option[Int]]("rating") //rating is nullable
        def * = (name, rating) <> (Foo.tupled, Foo.unapply)
      }
      

      如果你想让某些东西可以为空,只需将其声明为Option 字段,这样它就可以理解并生成带有该特定字段为可空的 sql。

      上述设计与 Scala Option 设计无缝且完美。意思是Scala中的option直接转换为sql中的Nullable。

      在旧版本的 Slick 中

      您必须通过在列声明中显式传递 O.NotNull 来告诉特定列不为空,但在新版本的 slick 中不需要它

      【讨论】:

        【解决方案3】:

        不要在列的定义中使用选项。如果你有 Option[String] 列应该仍然是 String。

        def firstName = column[Option[String]]("first_name") //Bad
        def firstName = column[String]("first_name") //Good
        

        当你定义 select (def *) 时使用 .?定义选项

          override def * =
            (id, uuid, version, task, firstName.?, lastName.?, ageGroup.?, incomeLevel.?, employmentStatus.?, maritalStatus.?, housingStatus.?, educationStatus.?, gender.?) <> (Respondent.tupled, Respondent.unapply)
        

        如果你想更新(在 TableQuery 中):

        def updateExistingName(name : String) : DBIO[Int] =
        {
            map(_.firstName).update(name)
        }
        
        def updateOptionName(nameCanBeNone: Option[String]) : DBIO[Int] =
        {
            map(_.firstName.?).update(nameCanBeNone)
        }
        

        【讨论】:

        • 您能否分享一下为什么不应该在列定义中使用Option
        • 如果该列可以为空,则必须使用 Option。
        • 不,您应该在列方法类型参数中使用 Option[String]。如果数据库在没有输入的情况下自动设置值,请不要使用?
        • Essential Slick 表示use Option in column def too
        猜你喜欢
        • 1970-01-01
        • 2019-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多