我正在尝试在Squeryl中创建自定义字段类型。此字段表示Isin code,因此它由字符串字段备份。在example on the documentation之后,我在创建新的isin之前添加了一个简单的验证(更不用说Isin代码是什么或验证过程如何工作):
trait Domain[A] { self: CustomType[A] =>
def validate(a: A): Unit
validate(value)
}
class Isin(v: String) extends StringField(v) with Domain[String] {
println("instantiating Isin")
override def validate(s: String) {
println("calling validate with " + s)
assert(checkIsin(s))
}
private def checkIsin(isin: String): Boolean = {
// never mind the exact procedure
}
}
我添加了一些println
来了解发生了什么。我在像
case class Asset(
val id: Long = 0,
val isin: Isin
) extends KeyedEntity[Long]
object Asset {
import Database.assets
def create(isinCode: String) {
inTransaction {
assets.insert(new Asset(isin = new Isin(isinCode)))
}
}
}
现在,当我调用Asset.create("US0378331005")
(一个有效的ISIN)时,我得到一个例外。在堆栈跟踪中,事实证明此异常是由于init
上的null
方法调用,该值应该传递给checkIsin
。实际上,println
语句打印
calling validate with US0378331005
Instantiating Isin
calling validate with
所以似乎validate
方法实际上被调用了两次,但第二次获得了null
值。
出了什么问题?
答案 0 :(得分:1)
这里有几个问题。首先,您似乎正在使用Lift Record,如果是这种情况,您将错误地实现验证逻辑。验证记录字段的正确方法是覆盖
def validations: List[ValidationFunction]
其中ValidationFunction是类型别名
type ValidationFunction = ValueType => List[FieldError]
在您的情况下,ValueType == String。
下一个问题是你的领域特质。因为您对validate的调用被内联到类定义中,所以在构造字段时将调用它。显然,此时没有设置值,因此这就是您看到引用空值的println的原因。我想你看到它们的顺序与你的应用程序流程有关。您有一个已验证的现有记录,然后创建一个新记录,触发接下来的两个println语句。