【问题标题】:How to use JSF ListDataModel object in abstract JPA criteria query如何在抽象 JPA 条件查询中使用 JSF ListDataModel 对象
【发布时间】:2015-10-08 19:35:06
【问题描述】:

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

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

抽象类的实现是:

@Stateless
public class ExportFacade extends AbstractFacade<Export> {

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

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

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

上述方法的结果正确显示,一切正常。现在我想做完全相同的事情,但在 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());
}

使用相同的实现(和上面的抽象方法),列表不显示,错误控制台为空白。我可以使用这样的方法手动硬编码 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;
}

我想在一个抽象类中实现上述代码,而不是在整个应用程序中对其进行硬编码。将不胜感激任何指导。提前致谢!

【问题讨论】:

    标签: jsf jakarta-ee jpa jsf-2


    【解决方案1】:

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

    不要更改您的服务等级。继续从它返回List。确保在任何服务类中都没有任何 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 实现应该是不可序列化的。

    然后你可以在一个普通的 backing 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?

    【讨论】:

    • 感谢您的精彩提示。实际上,这个问题表明我需要了解多少 JSF 的 MVC 结构,我现在尝试实现您的建议。
    • 不客气。也许这有帮助:stackoverflow.com/questions/30639785
    • 是的,当然有用!我需要剖析你写的东西。然而,我首先关心的是 ViewScoped。每当我使用 Session 范围以外的任何东西时,bean 都会失去持久性方法的焦点。我已经习惯了 pre-CDI bean。也许 CDI 中的 ViewScoped 效果更好?
    • 确保从正确的包中导入@ViewScoped。那里有两个;一个用于 JSF 托管 bean,另一个用于 CDI 托管 bean。错误的导入会有效地使 bean 表现得像 request/none scoped。
    猜你喜欢
    • 2011-06-20
    • 1970-01-01
    • 2012-03-21
    • 2015-07-01
    • 1970-01-01
    • 2012-06-04
    • 2011-05-04
    • 1970-01-01
    • 2012-02-18
    相关资源
    最近更新 更多