Grails数据绑定和瞬态

Grails数据绑定和瞬态,grails,data-binding,grails-2.4,Grails,Data Binding,Grails 2.4,考虑以下类别: Class Timesheet { BigDecimal hoursWorked Boolean reviewedByCustomer Boolean approvedByCustomer ... } 时间表在客户审核方面可以有三种状态: 待检查(reviewedByCustomer==false&&approvedByCustomer==null) 已批准(reviewedByCustomer==true和&approvedByCustomer

考虑以下类别:

Class Timesheet {
    BigDecimal hoursWorked
    Boolean reviewedByCustomer
    Boolean approvedByCustomer
    ...
}
时间表在客户审核方面可以有三种状态:

  • 待检查(
    reviewedByCustomer==false&&approvedByCustomer==null
  • 已批准(
    reviewedByCustomer==true和&approvedByCustomer==true
  • 拒绝(
    revievedbycustomer==false&&approvedByCustomer==false
  • 我想使用枚举类型
    ReviewStatus
    来表示这些状态,这些状态可以从时间表中检索或用于更新时间表。不得再使用这两个布尔值。使用以下参数映射:
    [reviewStatus:'APPROVED']
    ,数据绑定应按如下方式工作

    def timesheet = new Timesheet(params)
    

    应按如下方式检查状态:

    if(timesheet.reviewStatus == ReviewStatus.TO_BE_REVIEWED){
        //do Logic
    }
    
    为了实现这种行为,我使用了瞬态属性和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(对象,参数,[exclude:[])
    。我假设空映射会阻止瞬态属性自动添加到排除列表中

    我更喜欢使用bindable约束,因为这是一个比每次将数据绑定到时间表时传递空映射更干净的解决方案

    使用Grails2.4.2

    编辑1:使用Grails 2.4.2数据绑定器,而不是spring数据绑定器。

    上的项目演示了一种方法

    域类:

    // 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
        }
    }
    

    问题中有很多噪音。我真的不知道你想要什么。我编写了数据绑定器,我很乐意帮助您提供数据绑定建议,但我不明白基于这个冗长的问题,您想做什么。您是如何编写getter/setter方法的?@JeffScottBrown对于这个不完整的问题,我很抱歉,但我很赶时间。我重新措辞了这个问题,希望它现在更具可读性。@EmmanuelRosa我添加了源代码。整个问题是否只是想知道如何将数据绑定到一个不受字段支持的枚举属性?上面的建议假设您使用的是2.4.2中的默认数据绑定器,而不是不推荐的Spring数据非常感谢你花时间测试这个。这正是我希望它的工作方式,也可以使用
    新时间表(参数)
    。你也试过吗?我还没有尝试使用map构造函数。此外,我正在使用2.4.2。数据绑定器。“这正是我希望它工作的方式,只是在使用新的时间表(params)时也是如此”——这就是这个测试所做的<代码>参数是一个
    映射
    。上面的测试调用的构造函数与
    newtimesheet(params)
    在控制器中调用的构造函数相同。是的,我刚刚意识到了这一点。我目前正试图编写一个单元测试来重现我的问题。也许可以用它作为起点。
    // 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
        }
    }