0

我正在尝试在 Squeryl 中创建自定义字段类型。该字段表示一个Isin 代码,因此它由一个字符串字段支持。按照文档中的示例,我在创建新的 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值。

出了什么问题?

4

1 回答 1

1

这里有几个问题。首先,您似乎正在使用 Lift Record,如果是这种情况,您正在错误地实现您的验证逻辑。验证记录字段的正确方法是覆盖

def validations: List[ValidationFunction]

其中 ValidationFunction 是类型别名

type ValidationFunction = ValueType => List[FieldError]

在您的情况下,ValueType == String。

下一个问题是您的域特征。因为您对 validate 的调用已内联到类定义中,所以将在构造字段时调用它。显然,此时没有设置任何值,这就是为什么您看到 println 引用了一个空值。我想您看到它们的顺序与您的应用程序流程有关。您有一个已验证的现有记录,然后创建一个新记录,触发接下来的 2 个 println 语句。

于 2012-09-03T21:06:09.393 回答