交换唯一属性值后,Grails验证失败

| 交换唯一属性值后,Grails验证失败 嗨,我正在尝试创建一个界面,用户可以在其中创建一些自定义枚举以及不同语言的翻译。例如,用户可以创建枚举“电影类型”。对于此枚举,可能存在一个枚举值\“喜剧\”,对于该值,可能存在一种或多种语言的多种枚举值转换。 由于特定语言只能进行一次翻译,因此我向枚举值翻译域类添加了唯一约束。这些是我现在的域类:
class Enumeration {
    String label
    List<EnumerationValue> enumerationValues = new ArrayList<EnumerationValue>()

    static hasMany = [ enumerationValues: EnumerationValue ]
    static constraints = {
        label(nullable: false, blank: false)
        enumerationValues(nullable: true)
    }
}


class EnumerationValue {
    String label
    List<EnumerationValueTranslation> enumerationValueTranslations = new ArrayList<EnumerationValueTranslation>()

    static belongsTo = [ enumeration: Enumeration ]
    static hasMany = [ enumerationValueTranslations: EnumerationValueTranslation ]

    static constraints = {
        label(nullable: false, blank: false, unique: \'enumeration\')
        enumeration(nullable: false) 
        enumerationValueTranslations(nullable: false)
    }
}


class EnumerationValueTranslation {
    String value
    Language language

    static belongsTo = [ enumerationValue: EnumerationValue ]

    static constraints = {
        value(nullable: false, blank: false)
        language(nullable: true, unique: \'enumerationValue\')
        enumerationValue(nullable: false)

        /* unique constraint as mentioned in description text */
        language(unique: \'enumerationValue\')
    }
}
到目前为止,效果还不错。当我以一种语言互换的方式更新同一枚举值的两个枚举值转换时,会出现我的问题。例如我有一个 枚举值:\“喜剧\” 以及某些语言“不小心”混在一起的翻译 \“喜剧\”的翻译 语言:德语,值:“喜剧” 语言:英语,值\“Komödie\” 如果用户认识到他混用了某种语言,则可能要交换语言并再次保存枚举。这是发生我的错误的地方,因为在交换语言之后,枚举值转换唯一约束会验证为false。 为了调试这个问题,我只是试图在处理参数前后打印出导致翻译的错误,所以:
Enumeration enumeration = Enumeration.get(params[\'id\']);

println \"before:\"
enumeration.enumerationValues.each() { enumValue ->
    enumValue.enumerationValueTranslations.each() { enumValueTr ->
        println enumValueTr;
        if(!enumValueTr.validate()) {
            // print errors...
        }
    }
}

// swap languages:
// (this are the lines of codes that are actually executed, and cause the 
// error. The actual processing of params looks different of course...)

// sets the language of \"Comedy\" to English
EnumerationValueTranslation.get(5).language = Language.get(1);
// sets the language of \"Komödie\" to German
EnumerationValueTranslation.get(6).language = Language.get(2);


println \"after:\"
enumeration.enumerationValues.each() { enumValue ->
    enumValue.enumerationValueTranslations.each() { enumValueTr ->
        println enumValueTr;
        if(!enumValueTr.validate()) {
            // print errors...
        }
    }
}
将结果复制到:
before:
EnumerationValueTranslation(value: Fantasy, language: en_US, enumerationValue: Fantasy)
EnumerationValueTranslation(value: Phantasie, language: de_DE, enumerationValue: Fantasy) 

EnumerationValueTranslation(value: Comedy, language: de_DE, enumerationValue: Comedy)
EnumerationValueTranslation(value: Komödie, language: en_US, enumerationValue: Comedy)


after:
EnumerationValueTranslation(value: Fantasy, language: en_US, enumerationValue: Fantasy)
EnumerationValueTranslation(value: Phantasie, language: de_DE, enumerationValue: Fantasy)

EnumerationValueTranslation(value: Comedy, language: en_US, enumerationValue: Comedy)
    validation fails: Property [language] of class [Translation] with value [Language(code: en_US)] must be unique
EnumerationValueTranslation(value: Komödie, language: de_DE, enumerationValue: Comedy)
    validation fails: Property [language] of class [Translation] with value [Language(code: de_DE)] must be unique
在此状态下,我尚未删除或保存(或以任何方式刷新)任何内容-这只是更改对象后的结果。正如您所看到的,实际数据中确实没有任何不一致,并且验证不会失败。 我更改翻译的方式可能有误吗?我只是通过ID来获取它们,然后只是更新了语言-我在一个简单的示例中进行了尝试,并在那里工作了... 如果我仅创建所有枚举值和枚举值转换的深层副本并将其存储(这意味着验证确实不会失败),它也可以工作,但是我认为这确实不是应该的方式完成... 另一个奇怪的事情是,仅当我遍历数据时,验证才会失败。如果我完全不接触数据,则不会发生任何错误,但也不会保存数据,这意味着以下几行将导致对验证的评估:
enumeration.enumerationValues.each() { ev ->
    ev.enumerationValueTranslations.each() { evt ->

    }
}
那就是为什么我坚信必须存在一些非同寻常的问题...如果您还有其他需要知道的地方,请告诉我。 谢谢你的帮助     
已邀请:
        让我再试一次:) 我正在看
UniqueConstraint.processValidate()
,并且可以假设它的逻辑未考虑交换情况。 特别是代码
    boolean reject = false;
    if (id != null) {
        Object existing = results.get(0);
        Object existingId = null;
        try {
            existingId = InvokerHelper.invokeMethod(existing, \"ident\", null);
        }
        catch (Exception e) {
            // result is not a domain class
        }
        if (!id.equals(existingId)) {
            reject = true;
        }
    }
    else {
        reject = true;
    }
应该迭代获得的
results
并验证字段值STILL是否违反唯一性。如果进行交换,则应从缓存中选择另一个实例,并具有新的字段值。 因此,我建议您创建一个自己的
UniqueConstraint
的后代并使用它,除非有人要修补Grails。     

要回复问题请先登录注册