Grails 数据绑定(bind)和 transient

标签 grails data-binding grails-2.4

考虑以下类:

Class Timesheet {
    BigDecimal hoursWorked
    Boolean reviewedByCustomer
    Boolean approvedByCustomer
    ...
}

就客户评论而言,时间表可以具有三种状态:
  • TO_BE_CHECKED (reviewedByCustomer == false && approvedByCustomer == null)
  • 已批准 (reviewedByCustomer == true && approvedByCustomer == true)
  • 拒绝 (reviewedByCustomer == false && approvedByCustomer == false)

  • 我想使用枚举类型 ReviewStatus表示可以从时间表中检索或用于更新时间表的这些状态。不再使用这两个 bool 值。使用以下参数映射:[reviewStatus:'APPROVED'] ,数据绑定(bind)应该如下工作。
    def timesheet = new Timesheet(params)
    

    或者
    bindData(timesheet, params)
    

    应按如下方式检查状态:
    if(timesheet.reviewStatus == ReviewStatus.TO_BE_REVIEWED){
        //do Logic
    }
    

    为了实现这种行为,我使用了一个 transient 属性以及 getter 和 setter 方法:
    ...
    
    //reviewStatus does only exist as getter and setter methods, not as fields
    static transients = ['reviewStatus']
    
    ReviewStatus getReviewStatus(){
        if(reviewedByCustomer == false && approvedByCustomer == null){
            ReviewStatus.TO_BE_REVIEWED
        } else if(reviewedByCustomer == true && approvedByCustomer == true){
            ReviewStatus.APPROVED 
        } else if(reviewedByCustomer == true && approvedByCustomer == false){
            ReviewStatus.DENIED
        }
    }
    
    void setReviewStatus(ReviewStatus reviewStatus){
        if(reviewStatus == ReviewStatus.TO_BE_REVIEWED){
            reviewedByCustomer = false
            approvedByCustomer = null
        } else if(reviewStatus == ReviewStatus.APPROVED){
            reviewedByCustomer = true
            approvedByCustomer = true
        } else if(reviewStatus == ReviewStatus.DENIED){
            reviewedByCustomer = true
            approvedByCustomer = false
        }
    }
    ...
    

    但是,它不起作用。甚至没有 bindable:true .我发现这是类似问题的答案,但他们似乎一直在使用早期版本的 Grails。我可以让它工作的唯一方法是使用 bindData(object, params, [exclude:[]]) .我假设空映射会阻止 transient 属性自动添加到排除列表中。

    我更喜欢使用可绑定(bind)约束,因为这比每次将数据绑定(bind)到时间表时都传递一个空映射更简洁

    使用 Grails 2.4.2。

    编辑 1:使用 Grails 2.4.2 数据绑定(bind)器,而不是 Spring 数据绑定(bind)器。

    最佳答案

    该项目位于https://github.com/jeffbrown/enumprop演示了一种方法来做到这一点。

    域类:

    // grails-app/domain/demo/Timesheet.groovy
    package demo
    
    class Timesheet {
        Boolean reviewedByCustomer
        Boolean approvedByCustomer
    
        static transients = ['reviewStatus']
    
        ReviewStatus getReviewStatus(){
            if(reviewedByCustomer == false && approvedByCustomer == null){
                ReviewStatus.TO_BE_REVIEWED
            } else if(reviewedByCustomer == true && approvedByCustomer == true){
                ReviewStatus.APPROVED
            } else if(reviewedByCustomer == true && approvedByCustomer == false){
                ReviewStatus.DENIED
            }
        }
    
        void setReviewStatus(ReviewStatus reviewStatus){
            if(reviewStatus == ReviewStatus.TO_BE_REVIEWED){
                reviewedByCustomer = false
                approvedByCustomer = null
            } else if(reviewStatus == ReviewStatus.APPROVED){
                reviewedByCustomer = true
                approvedByCustomer = true
            } else if(reviewStatus == ReviewStatus.DENIED){
                reviewedByCustomer = true
                approvedByCustomer = false
            }
        }
    }
    

    单元测试:
    // test/unit/demo/TimesheetSpec.groovy
    package demo
    
    import grails.test.mixin.TestFor
    import spock.lang.Specification
    import spock.lang.Unroll
    
    @TestFor(Timesheet)
    class TimesheetSpec extends Specification {
    
        @Unroll('When reviewStatus is #reviewStatus reviewedByCustomer should be #reviewedByCustomer and approvedByCustomer should be #approvedByCustomer')
        void "test enum property binding"() {
            given:
            def timesheet = new Timesheet(reviewStatus: reviewStatus)
    
            expect:
            timesheet.reviewedByCustomer == reviewedByCustomer
            timesheet.approvedByCustomer == approvedByCustomer
    
            where:
            reviewStatus     | reviewedByCustomer | approvedByCustomer
            'APPROVED'       | true               | true
            'DENIED'         | true               | false
            'TO_BE_REVIEWED' | false              | null
        }
    
        @Unroll('When reviewedByCustomer is #reviewedByCustomer and approvedByCustomer is #approvedByCustomer then reviewStatus should be #reviewStatus')
        void "test retrieving the value of the enum property"() {
            given:
            def timesheet = new Timesheet(reviewedByCustomer: reviewedByCustomer,
                                          approvedByCustomer: approvedByCustomer)
    
            expect:
            timesheet.reviewStatus == reviewStatus
    
            where:
            reviewStatus                | reviewedByCustomer | approvedByCustomer
            ReviewStatus.APPROVED       | true               | true
            ReviewStatus.DENIED         | true               | false
            ReviewStatus.TO_BE_REVIEWED | false              | null
        }
    }
    

    关于Grails 数据绑定(bind)和 transient ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33679364/

    相关文章:

    Grails Controller 测试在渲染模板时对模型进行断言?

    javascript - 如何将 knockout 中的数据绑定(bind)到没有名称的数组

    c# - 使用 MVVM C#​​ 将 UpdateSourceTrigger 设置为 WPF ListBox 项源控件的显式

    mongodb - grails mongodb 3.0.2插件使用createCriteria()对关联进行联接查询

    grails - GSP包含-带参数-在g:内?

    java - 使用Geb提取Stackoverflow问题计数器

    windows - 运行标签不支持 WP7 中的数据绑定(bind)?

    jquery - Grails - jQuery UI 自动完成功能不起作用

    grails - 是否可以强制刷新保存在服务中的域?

    java - Grails中的电子邮件 validator 插件