1

I'm using JSF 2.0, PrimeFaces and OmniFaces.

I have 2 dialogs with <h:selectManyCheckbox>. The first dialog creates a new Course:

enter image description here

The Disciplinas are presented as:

<h:selectManyCheckbox id="disciplinas" 
    value="#{cursoMBean.listaDisciplinasDoCurso}"
    converter="omnifaces.SelectItemsConverter">
    <f:selectItems value="#{cursoMBean.listaTodasDisciplinas}"
        var="disciplina" itemValue="#{disciplina}"
        itemLabel="#{disciplina.nome}" />
</h:selectManyCheckbox>

This works fine. When I select some disciplines and submit the form, then the new Course with the selected Disciplines is properly inserted in the DB.

However, when I try to retrieve an existing Course from the DB, the saved Disciplines are not preselected.

enter image description here

The code is the same:

<h:selectManyCheckbox id="disciplinas" 
    value="#{cursoMBean.listaDisciplinasDoCurso}"
    converter="omnifaces.SelectItemsConverter">
    <f:selectItems value="#{cursoMBean.listaTodasDisciplinas}"
        var="disciplina" itemValue="#{disciplina}"
        itemLabel="#{disciplina.nome}" />
</h:selectManyCheckbox>

Here's the backing bean:

private ArrayList<Disciplina> listaTodasDisciplinas;
private ArrayList<Disciplina> listaDisciplinasDoCurso;

public CursoMBean() {
    if (listaTodasDisciplinas == null) {
        listaTodasDisciplinas = controleDisciplina.consulta();
    }

    if (listaDisciplinasDoCurso == null) {
        listaDisciplinasDoCurso = new ArrayList<Disciplina>();
    }
}

// When user selects one Course to edit, this method is called:
public void setSelecionado(Curso selecionado) {
    this.selecionado = selecionado;

    if (selecionado != null) {
        listaTodasDisciplinas = controleDisciplina.consulta();
        listaDisciplinasDoCurso = controleCurso.listaDisciplinasAssociadas(selecionado);
    }
}

Here's the Disciplina entity:

public class Disciplina {

    private int id;
    private String nome;

    public Disciplina() {
    }

    public Disciplina(int id, String nome) {
        this.id = id;
        this.nome = nome;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        if (!(nome.isEmpty() || nome == " " || nome == "  ")){
            this.nome = nome;
        }
    }

}

How is this caused and how can I solve it?

4

1 回答 1

2

默认情况下,实体的SelectItemsConverter依赖项与所选项目匹配。toString()但是,您的实体没有toString()实现,因此依赖于默认fqn@hashcode结果,当创建两个物理上不同Disciplina的实例时,即使它们具有相同的值,默认结果也不相同。

您基本上有 2 个选项,在SelectItemsConverter showjavadoc中也有提示:

  1. 实现一个toString唯一标识实体并且作为标识符有意义的方法。例如,

    @Override
    public String toString() {
        return String.format("%s[id=%d]", getClass().getSimpleName(), getId());
    }
    

    (请注意,这toString()是这样设计的,您可以轻松地将其保存在所有实体的抽象基类中,这样您就不需要在所有实体上复制粘贴相同的内容)

  2. 或者,如果toString()由于某种原因无法实现这样的 a (例如,依赖于之后无法修改的生成的类(无论是生成器模板)),那么扩展转换器如下:

    @FacesConverter("disciplinaSelectItemsConverter")
    public class DisciplinaSelectItemsConverter extends SelectItemsConverter {
    
        @Override
        public String getAsString(FacesContext context, UIComponent component, Object value) {
            Integer id = (value instanceof Disciplina) ? ((Disciplina) value).getId() : null;
            return (id != null) ? String.valueOf(id) : null;
        }
    
    }
    

    (注意:你真的应该使用Integer而不是int作为 ID,这int不能是null代表全新和未持久实体的正确方法)

    并按如下方式使用

    <h:selectManyCheckbox ... converter="disciplinaSelectItemsConverter">
    
于 2013-11-19T11:01:12.343 回答