我正在使用最新的 SORM v0.3.15与MySQL。
是否可以将特征用作实体的字段类型?因为我想实现以下内容:
trait Votable
case class Post(...) extends Votable
case class Comment(...) extends Votable
case class VoteHistory(.., source: Votable)
由于sorm的工作方式(反射等),我对它有一些疑问
现在我有一个例外Caused by: sorm.core.SormException: Unsupported type: models.entities.Votable
答案 0 :(得分:1)
根据源代码,您的Votable
类型应为以下之一:Range,Seq,Set,Map,Option,AnyVal,String,BigDecimal, Date,Time ,Enumeration,Tuple1 -22,或案例类。
有关详细信息,请查看./src/main/scala/sorm/mappings/MappingKind.scala
。这是一个片段:
sealed trait MappingKind
object MappingKind {
case object Enum extends MappingKind
case object Entity extends MappingKind
case object Value extends MappingKind
case object Tuple extends MappingKind
case object OptionToTable extends MappingKind
case object OptionToNullable extends MappingKind
case object Seq extends MappingKind
case object Set extends MappingKind
case object Map extends MappingKind
case object Range extends MappingKind
def apply
( reflection : Reflection )
: MappingKind
= reflection match {
case _
if reflection <:< Reflection[scala.Range]
=> Range
case _
if reflection <:< Reflection[collection.Seq[_]]
=> Seq
...
case _
if (reflection <:< Reflection[Tuple1[_]])
|| (reflection <:< Reflection[Tuple2[_, _]])
|| (reflection <:< Reflection[Tuple3[_, _, _]])
...
|| (reflection <:< Reflection[Tuple22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]])
=> Tuple
case _
if reflection.isCaseClass
=> Entity
case _
=> throw new SormException("Unsupported type: " + reflection)
}
}
支持的数据类型doc。
在那里使用的反射测试是./src/main/scala/sorm/reflection/Reflection.scala
:
def isCaseClass
= s match {
case s : ClassSymbol => s.isCaseClass
case _ => false
}
Votable
的问题在于它不是任何这些列出类型的子类型。因此,Scala无法确保Votable
的子类符合MappingKind
的子类型。换句话说,不能保证你不会这样做:class A extends Votable
不能被Sorm序列化,然后它会在运行时爆炸。
现在问题很明显,所以我们希望例如将Votable
作为一个案例类并从其中继承另一个案例类,但由于违反等规则,这在Scala中是不允许的。此外,Scala中没有统一的类型标记为案例类。
例如,尝试伪造“案例类类型”失败:
scala> trait Votable
defined trait Votable
scala> case class Comment(b: String) extends Votable
defined class Comment
scala> def isCaseClassOrWhat_?(v: AnyRef): Boolean = {
| import reflect.runtime.universe._
| val typeMirror = runtimeMirror(v.getClass.getClassLoader)
| val instanceMirror = typeMirror.reflect(v)
| val symbol = instanceMirror.symbol
| symbol.isCaseClass
| }
isCaseClassOrWhat_$qmark: (v: AnyRef)Boolean
scala> isCaseClassOrWhat_?(new Votable {});
res0: Boolean = false
scala> isCaseClassOrWhat_?(Comment("df"));
res1: Boolean = true
scala> trait VotableCaseClass extends Product with Serializable
defined trait VotableCaseClass
scala> isCaseClassOrWhat_?(new VotableCaseClass { def canEqual(that: Any): Boolean = ???; def productArity: Int = ???; def productElement(n: Int): Any = ??? });
res2: Boolean = false
如果我正确阅读Scala编译器代码,我只能理解isCaseClass
是由类上的编译器设置CASE
标志实现的,isCaseClass
测试是否存在此标志。< / p>
我不知道如何解决这个特殊问题。也许Storm可以为此设置另一个案例/标记界面。它可以是结构类型检查或Product with Serializable
或沿着这些线的东西。也许用Scala宏可以做到这一点 - 我对它们还不太了解。
编辑:
您可以使用Map
类型进行序列化,并将案例类转换为Map
,如下所示:
def caseClassToMap(cc: Product): Map[String,Any] = {
val fields = cc.getClass.getDeclaredFields.map(_.getName)
fields.zip(cc.productIterator.to).toMap
}
scala> case class A(a: Int)
defined class A
scala> caseClass2Map(A(123))
res14: scala.collection.immutable.Map[String,Any] = Map(a -> 123)
我没有测试它是否适用于SORM。