Scala 反射和 Squeryl
Posted
技术标签:
【中文标题】Scala 反射和 Squeryl【英文标题】:Scala reflection and Squeryl 【发布时间】:2013-08-23 15:59:59 【问题描述】:我正在使用 Scala、Scalatra 和 Squeryl 进行我的第一个大型项目,并遇到以下问题: 我想为我的 DAO 提供一个抽象基类,它提供基本 CRUD 操作(创建、读取、更新、删除)的简单实现,因此我需要一种方法让所述抽象基类知道要引用哪个表。
使用 Squeryl,您可以将数据类映射到扩展 squeryl.Schema 的单例对象中的实际表,并且您的 DAO 通常是每个类的伴随对象。
我想出了以下使用类型标签的解决方案:
首先,所有 DAO 都将继承的基类的摘录(注意:DBRecord 是 Squeryl 的 KeyedEntity 的子类):
abstract class CrudOps[S <: DBRecord](implicit tt: TypeTag[S])
def create(item: S)=
inTransaction
val result = ATSchema.recordTable.insert(item)
接下来,ATSchema中的recordTable函数:
object ATSchema extends Schema
val users = table[User]
def recordTable[T <: DBRecord](implicit tt: TypeTag[T]): Table[T] = tt.tpe match
case t if t =:= typeOf[User] => users.asInstanceOf[Table[T]]
//...other table types go here
case _ => throw new IllegalArgumentException("Unknown DBRecord type")
现在,这行得通,我有几张桌子,CrudOps 抓住正确的一张并做它的事情。但是有些东西我不明白(我对 Scala 还是很陌生):为什么我需要将 recordTable() 中的表 val 转换为 Table[T]?如果我删除 .asInstanceOf,我会得到类型不匹配,但用户的类型是 Table[User]... 似乎应该是不必要的。此外,这感觉应该是一个微不足道的问题的复杂解决方案(也许我正在滥用类型系统),并且还将 CrudOps 与 Schema 耦合(我想避免),所以我当然愿意来自比我有更多 Scala 和/或 Squeryl 经验的人的建议 :)
【问题讨论】:
删除演员表时出现的编译器错误是什么?您知道 Schema.findTablesFor 是一种根据表在 Schema 中表示的类型来查找表的方法吗? 不,不,我不知道 :)。我最终只是在其构造函数中将表格传递给 CrudOps,这样看起来更干净,更简单......不敢相信我之前没有想到它。我想我应该多睡点。 【参考方案1】:这不是真正的 Squeryl 东西。据我了解,问题在于模式匹配测试是在运行时完成的,在发生类型擦除之后。 Scala 能够使用 TypeTag 保留类型信息并执行运行时检查,但它不能在编译时推断类型是正确的。如果你想尝试类似的东西
case t: ClassTag[User] => users
如果要求编译器进行静态检查,您会收到用户类型已删除的警告。您这样做的方式应该可以工作,因为在您验证类型后执行强制转换应该没问题,我认为没有更好的方法。
【讨论】:
感谢您的解释,这与我的怀疑相符。不过,最后我选择了一个不依赖反射的更简单的解决方案:) 我认为你很好,但我想确保 Squeryl 的问题都有答案,以防其他人遇到它们。抱歉,花了这么长时间才回复你,你在度假时抓到我了 :)以上是关于Scala 反射和 Squeryl的主要内容,如果未能解决你的问题,请参考以下文章
通过 Java 反射找到 Scala 类型的伴生对象的可靠方法是啥?