如何在抽象 JPA 条件查询中使用 JSF ListDataModel 对象

How to use JSF ListDataModel object in abstract JPA criteria query

我正在使用 JPA 2 EclipseLink 开发 JSF 应用程序。我需要使用我的列表的 ListDataModel 实现而不是普通的 List 实现。我想把这个方法放在一个抽象外观 class 中,这样它就可以在整个应用程序中使用。对于普通的 List 实现,抽象 class

public List<T> findAll() {
    javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
    cq.select(cq.from(entityClass));
    return getEntityManager().createQuery(cq).getResultList();
}

抽象class实现是:

@Stateless
public class ExportFacade extends AbstractFacade<Export> {

    @PersistenceContext(unitName = "GazpromModulePU")
    private EntityManager em;

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    public ExportFacade() {
        super(Export.class);
    }

上述方法的结果正确显示,一切正常。现在我想做完全相同的事情,但 return ListDataModel 中的结果。我试过了:

public ListDataModel<T> findAllListDataModel() {
    javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
    cq.select(cq.from(entityClass));
    return new ListDataModel<T>(getEntityManager().createQuery(cq).getResultList());
}

使用相同的实现(和上面的抽象方法),列表不显示,错误控制台是 blank.I 可以使用如下方法手动硬编码 ListDataModel:

public ListDataModel<Export> hardCodedMethod() {
    if(someList == null) {
         someList = makeModel();
    }
    return someList;
}

public ListDataModel<Export> makeModel() {
    List<Export> elist = myFacade.findAll();
    ListDataModel<Export> model = new ListDataMOdel<Export>(eList);
    return model;
}

我想抽象地实现上述代码 class 而不是在整个应用程序中对其进行硬编码。非常感谢任何指导。提前致谢!

首先,您不应该在服务中包含任何 JSF 工件 class。这将您的业务层与当前的 Web 层紧密耦合。换句话说,您的业务层不可跨不同的 Web 层重用,例如 RESTful、Websockets、普通 JSP/Servlet 等

不要更改您的服务 class。继续从中返回 List。确保在任何服务 class 中没有任何 import javax.faces.*** 行。改为在 JSF 端解决您的问题。例如。创建一个抽象支持 bean。

public abstract class ListDataModelBacking<T> {

    private transient ListDataModel<T> model;

    public abstract List<T> getListFromService();

    public ListDataModel<T> getModel() {
        if (model == null) {
            model = new ListDataModel<>(getListFromService());
        }

        return model;
    }

}

请注意,DataModel 实现应该是不可序列化的。

然后你可以在常规的支持 bean 中使用它,如下所示:

@Named
@ViewScoped
public class FooBacking extends ListDataModelBacking<Foo> implements Serializable {

    @Inject
    private FooService fooService;

    @Override
    public List<Foo> getListFromService() {
        return fooService.listAll();
    }

}
<h:dataTable value="#{fooBacking.model}" ...>

或者,打 ListDataModel 并寻找一个更简单的解决方案来解决您试图通过在 bean 中使用 ListDataModel 属性 来解决的具体功能需求。也许 EL 2.2 能够传递方法参数?另见 a.o。 How can I pass selected row to commandLink inside dataTable?