【问题标题】:Unique constraint for repeated values重复值的唯一约束
【发布时间】:2012-11-06 02:30:05
【问题描述】:

我正在尝试 define a form in play! 2.0.4 具有以下属性和约束:

  1. 表单处理重复值(我们可以方便地假设这些值的类型为number)。所以这会让我们得到这样的结果:

    "numbers" -> list(number)
    
  2. 每个号码必须是唯一的,即对于所有其他提交的号码来说它必须是唯一的,并且对于数据库中已经存在的号码必须是唯一的(这可以通过一些函数@987654325进行检查@)。

  3. 表单错误应该是特定于数字的,不是唯一的。我不希望出现“有重复号码”的一般表单错误。

最好的方法是什么?

【问题讨论】:

    标签: forms scala playframework playframework-2.0 unique-constraint


    【解决方案1】:

    怎么样:

    def validateUnique(input: List[Int]): ValidationResult = {
    
      // Assuming check return true if the input num doesn't exist yet
      def check(num: Int): Boolean = num % 2 == 0
      val unique = input.toSet
      val dbDuplicates = unique.filterNot(check)
      val formDuplicates = input.diff(unique.toSeq)
      val duplicates = (dbDuplicates ++ formDuplicates).toList
    
      duplicates match {
        case List() => Valid
        case _ => Invalid("Duplicates: " + duplicates.mkString(", "))
      }
    }
    
    val uniqueConstraint = Constraint[List[Int]](validateUnique(_))
    

    然后你可以使用新的约束:

    mapping(
      ...,
      "ints" -> list(number).verifying(uniqueConstraint)
      ...
    

    【讨论】:

    • 这个答案很笼统。显然,如果你使用普通的 Scala 及其 API,这个问题很容易解决。我也熟悉在 Play 中编写复杂的表单验证。但是,关于第 3 点,我不太确定。我正在寻找更实用的解决方案,但感谢您的回答
    • @fynn 你的问题不是很准确,如果你只对第3点感兴趣,为什么要提到第1点和第2点?无论如何,我同意我的回答同样含糊不清,这是您问题的完整解决方案,希望您会喜欢它。
    【解决方案2】:

    这里的技巧是定义一个自定义的Constraint,类似于example。然后可以在Mapping[T] 上使用自定义Constraint 来使用verifying 方法验证表单中的字段。

    自定义Constraint 包含返回ValidationResult 的逻辑,即ValidInvalid。可以将错误消息传递给 Invalid 结果,您可以在其中指定数据库中重复或存在的内容。

    有关自定义验证的部分,请参阅 Play for Scala

    - 创建约束

      //Make this lazy to prevent java.lang.ExceptionInInitializerError at runtime.
      lazy val uniqueNumbersConstraint = Constraint[String](Some("Unique numbers constraint"), "")(checkNumbers)
    
      //"Business Logic". 
      //Important part here is that the function returns a ValidationResult and complies with the signature for Constraint. i.e. f: (T) => ValidationResult
      //Return Valid if n in numbers is not in database and there are no duplicates.   
      //Otherwise return Invalid and an error message showing what numbers are in the database or duplicated. 
      def checkNumbers(numbers: String):ValidationResult  = {
        val splitNums = numbers.split(" ").toList.map(_.toInt)
        val dbnums  = splitNums.partition(database.contains(_))
        if(dbnums._1.isEmpty && uniquesAndDuplicates(splitNums)._2.isEmpty){
          Valid
        }else{
          val duplicates = uniquesAndDuplicates(dbnums._2)._2
          val error = "Database contains: " + dbnums._1 + ", duplicated values: " + duplicates
          Invalid(error)
        }
      }
    

    - 使用自定义约束验证表单

      val helloForm = Form(
        tuple(
          "numbers" -> nonEmptyText.verifying(uniqueNumbersConstraint)
        ))
    

    - 实用程序

      //Return unique values on left side and duplicate values on right side
      def uniquesAndDuplicates(numbers: List[Int]):Tuple2[List[Int], List[Int]] = {
        numbers.partition(i => numbers.indexOf (i) == numbers.lastIndexOf(i))
      }
    
      def checkNum(num: Int) = {
        database.contains(num) 
      }
    
      val database = List(5,6,7)
    

    -等

    注意,我在表单中将numbers 定义为String。当我将其定义为list(number) 时,它一直评估为List()。我认为这是一个有约束力的问题。如果使用 list(number) 有效,则使用 List(1,2,3) 而不是 "1 2 3" 是一个相当简单的更改。

    - 样本

    【讨论】:

      猜你喜欢
      • 2022-01-13
      • 2020-03-27
      • 2013-06-23
      • 2016-06-12
      • 2013-03-15
      • 2016-11-27
      • 2018-03-14
      • 2016-09-27
      • 2019-07-22
      相关资源
      最近更新 更多