【问题标题】:How do I create and XOR validation for two fields in a Grails domain class?如何为 Grails 域类中的两个字段创建和异或验证?
【发布时间】:2012-07-13 22:11:48
【问题描述】:

我有一个问题,我的域类有两个潜在的互斥外部键,一个序列号或一个旧的查找值。

由于我不确定我将为任何给定条目使用哪一个,因此我将它们设为可为空并添加自定义验证以确保我只有一个值。

package myproject 

class Sample {

    String information
    String legacyLookup
    String serialNumber

    static constraints = {
        information(nullable: true)
        legacyLookup(nullable: true)
        serialNumber(nullable: true)

        legacyLookup validator: {
            return ((serialNumber != null && legacyLookup == null) || (serialNumber == null && legacyLookup != null))
        }

        serialNumber validator: {
            return ((serialNumber != null && legacyLookup == null) || (serialNumber == null && legacyLookup != null))
        }
    }
}

我创建了默认的 CRUD 屏幕并尝试为此域类创建一个条目

information: Blah Blah
serialNumber: 
legacyLookup: BLAHINDEX123

这在验证器中死亡,并显示以下消息:

No such property: serialNumber for class: myproject.Sample

我错过了什么?

【问题讨论】:

    标签: grails grails-domain-class grails-validation


    【解决方案1】:

    没有必要多次将每个属性放在其中;实际上,您只需要其中一个实际受约束。此外,您不能只通过名称直接引用属性。有些对象传递给约束闭包,用于获取值(请参阅docs)。可能我发现的最简单的方法如下:

    class Sample {
        String information
        String legacyLookup
        String serialNumber
    
        static constraints = {
            information(nullable: true)
            legacyLookup(validator: {val, obj->
                if( (!val && !obj.serialNumber) || (val && obj.serialNumber) ) {
                    return 'must.be.one'
                }
            })
        }
    }
    

    然后在messages.properties文件中有这样一个条目:

    must.be.one=Please enter either a serial number or a legacy id - not both
    

    或者您可以为每个条件设置单独的消息 - 都输入,或者都为空,如下所示:

    legacyLookup(validator: {val, obj->
        if(!val && !obj.serialNumber) {
             return 'must.be.one'
        }
        if(val && obj.serialNumber) { 
             return 'only.one'
        }
    })
    

    然后message.properties中有两条消息:

    only.one=Don't fill out both
    must.be.one=Fill out at least one...
    

    如果没有错误,则不需要从约束中返回任何内容...

    【讨论】:

    • 这正是我所需要的。我在想我需要在两个字段上明确地进行验证,但一个处理另一个。谢谢!
    【解决方案2】:

    如果您想确保拥有“一个且只有一个值”,另一种选择是创建一个名为 serialNumberLegacyLookup 的通用字段,该字段将代表 serialNumberlegacyLookup 字段。然后你可以在你的域类中添加一个布尔字段legacyLookup,默认为false。然后,您可以通过验证器运行该值并对其进行解析以查看它是“序列号”还是“旧版查找”值。如果该值被证明是“旧版查找”值,那么您可以将 legacyLookup 布尔值设置为 true。我认为从 UI 的角度来看,这种方法不会令人困惑(用户只需填写一个字段,而不是两个条件字段)。

    【讨论】:

    • 由于我正在使用的代码与外部遗留系统交互,我认为这个解决方案不合适。我收到的数据有一个字段或另一个字段,但它们被建模为唯一字段。目前可能有一些我不知道的业务规则可能会破坏我对模型的理解。为了使自己免受这种可能性的影响,我将把它们分开。
    【解决方案3】:

    我遇到了同样的情况,我找到的解决方案是创建一个 getter 方法并为其添加一个约束。

    package myproject 
    
    class Sample {
    
        String information
        String legacyLookup
        String serialNumber
    
        def getTarget(){
            if (legacyLookup && !serialNumber) {
                return legacyLookup
            } else if (!legacyLookup && serialNumber) {
                return serialNumber
            } else {
                return null
            }
        }
    
        static constraints = {
            information(nullable: true)
            legacyLookup(nullable: true)
            serialNumber(nullable: true)
            target(nullable: false)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-18
      • 2011-02-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多