通过缓存数据客户端避免在转换器类的getAsObject方法中额外的DB读取?

Raj*_*pta 5 jsf converter primefaces jsf-2

我在autocomplete输入元素中显示了建议项目列表.为此,我需要实现一个converter转换的entity<entityName, entityId>entityName反之亦然&.然而,在实现的时候,我意识到我必须读取数据库超过1次,以便为所选的entityName(while getAsObject())找到相应的entityId ,我想知道为什么不将它存储在某个客户端,以便entityId可以在entityname被选中.

有什么办法可以避免这种额外的阅读吗?

Bal*_*usC 6

这确实是"按设计",也许在JSF规范中有点疏忽.从理论上讲,你可以通过从UIComponent参数中提取项目并相反地对它们进行比较来完全避免它.然而,它有点工作.我的同事Arjan Tijms撰写了一篇关于此的博客:JSF selectOneMenu&Co.中的自动对象转换

这是相关的摘录; 以下是您需要扩展的基本转换器:

public abstract class SelectItemsBaseConverter implements Converter {
    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {        
        return SelectItemsUtils.findValueByStringConversion(context, component, value, this);    
    }    
}
Run Code Online (Sandbox Code Playgroud)

SelectItemsUtils是从Mojarra的源代码部分复制的类:

public final class SelectItemsUtils {

    private SelectItemsUtils() {}

    public static Object findValueByStringConversion(FacesContext context, UIComponent component, String value, Converter converter) {
        return findValueByStringConversion(context, component, new SelectItemsIterator(context, component), value, converter);        
    }

    private static Object findValueByStringConversion(FacesContext context, UIComponent component, Iterator<SelectItem> items, String value, Converter converter) {
        while (items.hasNext()) {
            SelectItem item = items.next();
            if (item instanceof SelectItemGroup) {
                SelectItem subitems[] = ((SelectItemGroup) item).getSelectItems();
                if (!isEmpty(subitems)) {
                    Object object = findValueByStringConversion(context, component, new ArrayIterator(subitems), value, converter);
                    if (object != null) {
                        return object;
                    }
                }
            } else if (!item.isNoSelectionOption() && value.equals(converter.getAsString(context, component, item.getValue()))) {
                return item.getValue();
            }
        }        
        return null;
    }

    public static boolean isEmpty(Object[] array) {
        return array == null || array.length == 0;    
    }

    /**
     * This class is based on Mojarra version
     */
    static class ArrayIterator implements Iterator<SelectItem> {

        public ArrayIterator(SelectItem items[]) {
            this.items = items;
        }

        private SelectItem items[];
        private int index = 0;

        public boolean hasNext() {
            return (index < items.length);
        }

        public SelectItem next() {
            try {
                return (items[index++]);
            }
            catch (IndexOutOfBoundsException e) {
                throw new NoSuchElementException();
            }
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是如何将它用于您自己的转换器,您只需实现getAsString()(getAsObject()已经处理):

@FacesConverter("someEntitySelectItemsConverter")
public class SomeEntitySelectItemsConverter extends SelectItemsBaseConverter {

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        return ((SomeEntity) value).getId().toString();
    }
}
Run Code Online (Sandbox Code Playgroud)

更新上面的概念已经在JSF实用程序库OmniFaces中结束了以下转换器的风格: