Поля Anorm и Enum - PullRequest
       20

Поля Anorm и Enum

2 голосов
/ 23 января 2012

Мне просто интересно, как я могу использовать поля enum (классы, расширенные от Enumeration) в моих классах с Anorm.Например:

object Type extends Enumeration {
    type Type = Value
    val User, Admin = Value
}

case class User (
    id: Pk[Long],
    type: Type.Type
)

Если я попробую такой код, я получу «RuntimeException: нет поддерживаемых конструкторов для моделей типов. Пользователь».Какой тип поля БД мне следует использовать для таких целей?Я попробовал varchar без удачи.

1 Ответ

1 голос
/ 13 февраля 2013

Вы можете сделать это, с отражением. Учитывая код ниже (scala 2.10), сделайте импорт как

import AnormEnumerationExtension.ToId._

и ваше перечисление сохраняется через его id. И если вы хотите сохранить это имя, используйте

import AnormEnumerationExtension.ToName._

Наконец, EnumExtension:

import java.lang.reflect.InvocationTargetException
import scala.reflect.runtime.universe._

object AnormEnumerationExtension {      
  private lazy val rm = scala.reflect.runtime.currentMirror

  object ToId {
    implicit def enumToParameterValue[E <: Enumeration: TypeTag](enumValue: E#Value): ParameterValue[Int] = enumValue.id

    implicit def rowToEnumValue[E <: Enumeration: TypeTag]: Column[E#Value] = Column.nonNull { (value, meta) =>
      val MetaDataItem(qualified, _, _) = meta
      value match {
        case int: Int => {
          val methodSym = typeTag[E].tpe.member(newTermName("apply")).asMethod
          val im = rm.reflect(rm.reflectModule(typeOf[E].termSymbol.asModule).instance)
          try {
            Right(im.reflectMethod(methodSym)(int).asInstanceOf[E#Value])
          } catch {
            case e: InvocationTargetException if e.getCause.isInstanceOf[NoSuchElementException] =>
              Left(SqlMappingError(s"Can't convert $int to ${typeTag[E].tpe}, because it isn't a valid value: $qualified"))
          }
        }
        case _ => Left(TypeDoesNotMatch(s"Can't convert [$value:${value.asInstanceOf[AnyRef].getClass}] to ${typeTag[E].tpe}: $qualified"))
      }
    }
  }

  object ToName {
    implicit def enumToParameterValue[E <: Enumeration: TypeTag](enumValue: E#Value): ParameterValue[String] = enumValue.toString

    implicit def rowToEnumValue[E <: Enumeration: TypeTag]: Column[E#Value] = Column.nonNull { (value, meta) =>
      val MetaDataItem(qualified, _, _) = meta
      value match {
        case string: String => {
          val methodSym = typeTag[E].tpe.member(newTermName("withName")).asMethod
          val im = rm.reflect(rm.reflectModule(typeOf[E].termSymbol.asModule).instance)
          try {
            Right(im.reflectMethod(methodSym)(string).asInstanceOf[E#Value])
          }
          catch {
            case e: InvocationTargetException if e.getCause.isInstanceOf[NoSuchElementException] =>
              Left(SqlMappingError(s"Can't convert '$string' to ${typeTag[E].tpe}, because it isn't a valid value: $qualified"))
          }
        }
        case _ => Left(TypeDoesNotMatch(s"Can't convert [$value:${value.asInstanceOf[AnyRef].getClass}] to ${typeTag[E].tpe}: $qualified"))
      }
    }
  }
}
...