Поля Anorm и Enum
Мне просто интересно, как я могу использовать enum fileds (классы, расширенные от Enumeration) в моих классах с Anorm. Например:
object Type extends Enumeration {
type Type = Value
val User, Admin = Value
}
case class User (
id: Pk[Long],
type: Type.Type
)
Если я попробую такой код, я получу "RuntimeException: нет поддерживаемых конструкторов для моделей типов.User". Какой тип поля БД мне следует использовать для таких целей? Я попробовал varchar без удачи.
1 ответ
Вы можете сделать это, с отражением. Учитывая код ниже (scala 2.10), выполните импорт как
import AnormEnumerationExtension.ToId._
и ваше перечисление сохраняется через его идентификатор. И если вы хотите сохранить это имя, используйте
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"))
}
}
}
}