Создание формы для объекта домена с множественным выбором поля Enum завершается сбоем из-за «Несоответствие типа свойства xxx»

Я использую Grails 4.0.4 с GORM 7.0.7.RELEASE. Я использую базу данных MongoDB.

Я могу успешно запустить приложение и перейти к форме создания для класса домена. Я могу выбрать значение для одноэлементного поля someOtherEnum. Я могу выбрать несколько значений для поля categories. Однако, когда я отправляю форму, я получаю это сообщение: «Категории свойств не соответствуют типу». Я использовал этот подход на основе ответов на другой вопрос, размещенный здесь, но он не работает для меня. Я не использую встроенное перечисление или коллекцию hasMany, как этот пользователь.

Контроллер и сервис были сгенерированы командой generate-all.

Как добавить несколько полей перечисления в формы создания и редактирования в Grails 4?

У меня есть перечисление, расположенное в src/main/groovy/com/project/core/dsl, которое я использую для заполнения поля множественного выбора для класса домена:

package com.project.core.dsl

import groovy.transform.CompileStatic

@CompileStatic
enum Category {
   CATEGORY_ONE("Category One"),
   CATEGORY_TWO("Category Two"),
   CATEGORY_THREE("Category Three")

   private final String id

   private Category(String id) { this.id = id }

   @Override
   String toString() { id }

   String getKey() { name() }
}

Класс домена:

package com.project.core

import com.project.core.dsl.SomeOtherEnum
import com.project.core.dsl.Category

class DomainObject {

    SomeOtherEnum someOtherEnum
    Set<Category> categories

    static constraints = {
    }

    static mapping = {
        someOtherEnum index: true
    }

    @Override
    String toString() {
        return "DomainObject{" +
            "someOtherEnum=" + someOtherEnum +
            ", categories=" + categories +
            '}';
    }
}

В представлении create.gsp у меня есть такая форма:

<g:form resource="${this.domainObject}" method="POST">
    <fieldset class="form">
        <f:with bean="domainObject">
            <f:field property="someOtherEnum"/>
            <f:field property="categories">
                <g:select
                    multiple="true"
                    name="${property}"
                    from="${Category}"
                    value="${domainObject?.categories}"
                />
            </f:field>
        </f:with>

    </fieldset>
    <fieldset class="buttons">
        <g:submitButton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'Create')}" />
    </fieldset>
</g:form>

Контроллер класса домена:

package com.project.core

import grails.validation.ValidationException
import static org.springframework.http.HttpStatus.*

class DomainObject {

    DomainObjectService domainObjectService

    static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]

    def index(Integer max) {
        params.max = Math.min(max ?: 10, 100)
        respond domainObjectService.list(params), model:[domainObjectCount: domainObjectService.count()]
    }

    def show(Long id) {
        respond domainObjectService.get(id)
    }

    def create() {
        respond new DomainObject(params)
    }

    def save(DomainObject domainObject) {
        if (domainObject == null) {
            notFound()
            return
        }

        try {
            domainObjectService.save(domainObject)
        } catch (ValidationException e) {
            respond domainObject.errors, view:'create'
            return
        }

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.created.message', args: [message(code: 'domainObject.label', default: 'DomainObject'), domainObject.id])
                redirect domainObject
            }
            '*' { respond domainObject, [status: CREATED] }
        }
    }

    def edit(Long id) {
        respond domainObjectService.get(id)
    }

    def update(DomainObject domainObject) {
        if (domainObject == null) {
            notFound()
            return
        }

        try {
            domainObjectService.save(domainObject)
        } catch (ValidationException e) {
            respond domainObject.errors, view:'edit'
            return
        }

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.updated.message', args: [message(code: 'domainObject.label', default: 'DomainObject'), domainObject.id])
                redirect domainObject
            }
            '*'{ respond domainObject, [status: OK] }
        }
    }

    def delete(Long id) {
        if (id == null) {
            notFound()
            return
        }

        domainObjectService.delete(id)

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.deleted.message', args: [message(code: 'domainObject.label', default: 'DomainObject'), id])
                redirect action:"index", method:"GET"
            }
            '*'{ render status: NO_CONTENT }
        }
    }

    protected void notFound() {
        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.not.found.message', args: [message(code: 'domainObject.label', default: 'DomainObject'), params.id])
                redirect action: "index", method: "GET"
            }
            '*'{ render status: NOT_FOUND }
        }
    }
}

Служба объекта домена:

package com.project.core

import grails.gorm.services.Service

@Service(DomainObject)
interface DomainObjectService {

    DomainObject get(Serializable id)

    List<DomainObject> list(Map args)

    Long count()

    void delete(Serializable id)

    DomainObject save(DomainObject domainObject)

}

person Selena    schedule 01.09.2020    source источник
comment
Является ли эта форма отправкой в ​​действие контроллера, которое использует встроенный связыватель данных для заполнения свойств экземпляра DomainObject?   -  person Jeff Scott Brown    schedule 01.09.2020
comment
@JeffScottBrown Контроллер — это просто сгенерированный контроллер, который вы получаете при использовании generate-all. Нужно ли мне что-то делать с классом Controller?   -  person Selena    schedule 01.09.2020


Ответы (1)


Я смог обойти свою ошибку, внеся следующие изменения. Я добавил оператор hasMany в DomainObject

static hasMany = [categories: Category]

и я сделал эти изменения в файле create.gsp:

<f:field property="categories">
    <g:select
         multiple="true"
         name="${property}"
         from="${Category?.values()}"
         optionKey="key"
         value="${domainObject?.categories}"
    />
</f:field>
person Selena    schedule 16.09.2020