2015-07-19 55 views
0

我正在使用JPA 2 EclipseLink开发JSF应用程序。我需要使用我的列表的ListDataModel实现,而不是普通的List实现。我想把这个方法放在一个抽象的facade类中,以便它可以在整个应用程序中使用。对于一个正常的列表实现抽象类如何在抽象JPA标准查询中使用JSF ListDataModel对象

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()); 
} 

使用相同的实现(和上面的抽象方法)时,不显示的列表和错误控制台是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; 
} 

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

回答

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实现应该是不可序列化的。

然后你就可以在常规支持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并寻找一个简单的解决方案的具体功能要求你尝试与具有解决ListDataModel bean中的属性。也许EL 2.2传递方法参数的能力?另见a.o. How can I pass selected row to commandLink inside dataTable?

+0

谢谢你的优秀提示。实际上,这个问题显示了我需要了解JSF的MVC结构,我现在试着实现你的建议。 –

+1

不客气。也许这是有帮助的:http://stackoverflow.com/questions/30639785/ – BalusC

+0

是的,当然它是有帮助的!我需要剖析你写的东西。然而,我首先关心的是ViewScoped。每当我使用Session范围以外的任何东西时,bean都会失去焦点并使用持久方法。我习惯了CDI之前的豆类。也许CDI中的ViewScoped效果更好? –