简体   繁体   English

Grails数据绑定和瞬态

[英]Grails Data Binding and Transients

Consider the following class: 考虑以下类别:

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

The timesheet can have three states in terms of customer review: 根据客户审查,时间表可以具有三种状态:

  1. TO_BE_CHECKED ( reviewedByCustomer == false && approvedByCustomer == null ) TO_BE_CHECKED(reviewByCustomer reviewedByCustomer == false && approvedByCustomer == nullreviewedByCustomer == false && approvedByCustomer == null ByCustomer reviewedByCustomer == false && approvedByCustomer == null
  2. APPROVED ( reviewedByCustomer == true && approvedByCustomer == true ) 批准( reviewedByCustomer == true && approvedByCustomer == true
  3. DENIED ( reviewedByCustomer == false && approvedByCustomer == false ) 拒绝( reviewedByCustomer == false && approvedByCustomer == false

I want to use an enum type ReviewStatus to represent these states that can be retrieved from a timesheet or used to update the timesheet. 我想使用一个枚举类型ReviewStatus来表示可以从时间表中检索或用于更新时间表的这些状态。 The two boolean values shall not be used anymore. 这两个布尔值将不再使用。 With the following parameter map: [reviewStatus:'APPROVED'] , data binding should work as follows . 使用以下参数映射: [reviewStatus:'APPROVED'] ,数据绑定应如下所示。

def timesheet = new Timesheet(params)

or 要么

bindData(timesheet, params)

The Status should be checked as follows: 应按以下方式检查状态:

if(timesheet.reviewStatus == ReviewStatus.TO_BE_REVIEWED){
    //do Logic
}

To achieve this behaviour, I use a transient property and getter and setter methods: 为了实现此行为,我使用了瞬态属性以及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
    }
}
...

However, it does not work. 但是,它不起作用。 Not even with bindable:true . 甚至没有bindable:true I found this as an answer for similar questions, but they seem to have been using an earlier version of Grails. 我发现这是对类似问题的解答,但他们似乎一直在使用Grails的早期版本。 The only way I could get it to work was by using bindData(object, params, [exclude:[]]) . 我可以使它工作的唯一方法是使用bindData(object, params, [exclude:[]]) I assume that the empty map prevents the transient properties from being added to the exclusion list automatically. 我认为空白映射会阻止将瞬态属性自动添加到排除列表中。

I would prefer to use the bindable constraint instead, because this would be a cleaner solution than passing an empty map every time I bind data to a timesheet 我宁愿改用可绑定约束,因为这比每次我将数据绑定到时间表时都传递一个空的映射要更清洁。

Using Grails 2.4.2. 使用Grails 2.4.2。

EDIT 1: Using Grails 2.4.2 data binder, not spring data binder. 编辑1:使用Grails 2.4.2数据绑定器,而不是spring数据绑定器。

The project at https://github.com/jeffbrown/enumprop demonstrates one way to do this. https://github.com/jeffbrown/enumprop上的项目演示了一种实现此目的的方法。

Domain Class: 域类:

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

Unit test: 单元测试:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM