2016-05-20 3 views
3

私は列の日付のテーブルを持っています。この列はnull値を受け入れるため、Optionとして宣言しました(下記perDateのフィールドを参照)。エラーで失敗perDateがnullのときに、この表からの読み取りなどの問題が明らかにから/ java.time.LocalDate/java.sql.Dateへの暗黙的な変換が間違っているということです。Slick 3.xでnull可能な日付の列を定義して読み取る

slick.SlickException: Read NULL value (null) for ResultSet column <computed> 

これは、暗黙的な機能を含むスリックテーブル定義、次のとおりです。

import java.sql.Date 
import java.time.LocalDate 

class FormulaDB(tag: Tag) extends Table[Formula](tag, "formulas") { 

    def sk = column[Int]("sk", O.PrimaryKey, O.AutoInc) 
    def name = column[String]("name") 
    def descrip = column[Option[String]]("descrip") 
    def formula = column[Option[String]]("formula") 
    def notes = column[Option[String]]("notes") 
    def periodicity = column[Int]("periodicity") 
    def perDate = column[Option[LocalDate]]("per_date")(localDateColumnType) 

    def * = (sk, name, descrip, formula, notes, periodicity, perDate) <> 
     ((Formula.apply _).tupled, Formula.unapply) 


    implicit val localDateColumnType = MappedColumnType.base[Option[LocalDate], Date](
    { 
     case Some(localDate) => Date.valueOf(localDate) 
     case None => null 
    },{ 
     sqlDate => if (sqlDate != null) Some(sqlDate.toLocalDate) else None 
    } 
) 

} 

答えて

0

Noneの代わりにnullをマッピング関数から返すことが問題だと私は確信しています。

LocalDateからDateに関数として、あなたのマッピング機能を書き換えてみます

implicit val localDateColumnType = MappedColumnType.base[LocalDate, Date](
    { 
    localDate => Date.valueOf(localDate) 
    },{ 
    sqlDate => sqlDate.toLocalDate 
    } 
) 

代わりに、Option[LocalDate]からOption[Date]へのマッピングは動作するはずです:

implicit val localDateColumnType = 
    MappedColumnType.base[Option[LocalDate], Option[Date]](
    { 
     localDateOption => localDateOption.map(Date.valueOf) 
    },{ 
     sqlDateOption => sqlDateOption.map(_.toLocalDate) 
    } 
) 
+0

'Option [LocalDate]'から 'Option [date]'にマップする方法は?列は 'column [Option [LocalDate]]'として定義されているため、LocalDateからDateにはマッピングできません。 – ps0604

+0

また、関数 'localDate'と' sqlDate'は定義されていません – ps0604

+0

私は関数リテラルを修正し、オプションマッピングの例を追加しました。 – jkinkead

3

実際に/へjava.time.LocalDate/java.sql.Dateからごimplicit conversionではありません間違っている。

Slick SQLコンパイラで作成されたノードが実際にMappedJdbcType[Scala.Option -> LocalDate]であり、Option[LocalDate]ではないことがわかったので、同じエラーが発生しました。マッピングコンパイラはデフあなたの列コンバータを作成する理由である

perDateそれがオプションResultConverter

がここにあるベースResultConverterなく作成されベースコンバータのSlick code

def base[T](ti: JdbcType[T], name: String, idx: Int) = (ti.scalaType match { 
    case ScalaBaseType.byteType => new BaseResultConverter[Byte](ti.asInstanceOf[JdbcType[Byte]], name, idx) 
    case ScalaBaseType.shortType => new BaseResultConverter[Short](ti.asInstanceOf[JdbcType[Short]], name, idx) 
    case ScalaBaseType.intType => new BaseResultConverter[Int](ti.asInstanceOf[JdbcType[Int]], name, idx) 
    case ScalaBaseType.longType => new BaseResultConverter[Long](ti.asInstanceOf[JdbcType[Long]], name, idx) 
    case ScalaBaseType.charType => new BaseResultConverter[Char](ti.asInstanceOf[JdbcType[Char]], name, idx) 
    case ScalaBaseType.floatType => new BaseResultConverter[Float](ti.asInstanceOf[JdbcType[Float]], name, idx) 
    case ScalaBaseType.doubleType => new BaseResultConverter[Double](ti.asInstanceOf[JdbcType[Double]], name, idx) 
    case ScalaBaseType.booleanType => new BaseResultConverter[Boolean](ti.asInstanceOf[JdbcType[Boolean]], name, idx) 
    case _ => new BaseResultConverter[T](ti.asInstanceOf[JdbcType[T]], name, idx) { 
     override def read(pr: ResultSet) = { 
     val v = ti.getValue(pr, idx) 
     if(v.asInstanceOf[AnyRef] eq null) throw new SlickException("Read NULL value ("+v+") for ResultSet column "+name) 
     v 
     } 
    } 
    }).asInstanceOf[ResultConverter[JdbcResultConverterDomain, T]] 

残念ながら、私はこの問題の解決策を持っていない、私は回避策として提案するものを、次のようにあなたのperDateプロパティをマッピングすることです。

import java.sql.Date 
import java.time.LocalDate 

class FormulaDB(tag: Tag) extends Table[Formula](tag, "formulas") { 

    def sk = column[Int]("sk", O.PrimaryKey, O.AutoInc) 
    def name = column[String]("name") 
    def descrip = column[Option[String]]("descrip") 
    def formula = column[Option[String]]("formula") 
    def notes = column[Option[String]]("notes") 
    def periodicity = column[Int]("periodicity") 
    def perDate = column[Option[Date]]("per_date") 

    def toLocalDate(time : Option[Date]) : Option[LocalDate] = time.map(t => t.toLocalDate)) 
    def toSQLDate(localDate : Option[LocalDate]) : Option[Date] = localDate.map(localDate => Date.valueOf(localDate))) 


    private type FormulaEntityTupleType = (Int, String, Option[String], Option[String], Option[String], Int, Option[Date]) 

    private val formulaShapedValue = (sk, name, descrip, formula, notes, periodicity, perDate).shaped[FormulaEntityTupleType] 

    private val toFormulaRow: (FormulaEntityTupleType => Formula) = { formulaTuple => { 
     Formula(formulaTuple._1, formulaTuple._2, formulaTuple._3, formulaTuple._4, formulaTuple._5, formulaTuple._6, toLocalDate(formulaTuple._7)) 
    } 
    } 

    private val toFormulaTuple: (Formula => Option[FormulaEntityTupleType]) = { formulaRow => 
    Some((formulaRow.sk, formulaRow.name, formulaRow.descrip, formulaRow.formula, formulaRow.notes, formulaRow.periodicity, toSQLDate(formulaRow.perDate))) 
    } 

    def * = formulaShapedValue <> (toFormulaRow, toFormulaTuple) 

うまくいけば、答えは遅すぎなくなります。

+0

答えがありがとう、私の回避策は、日付のデフォルト値を定義することでしたので、決してnullではありません – ps0604

+0

はい、それはあなたのケースであるあなたのDB定義にアクセスするときにも機能します。私の場合、私はテーブル定義を変更できませんでした。 – iilish

関連する問題