使用PrimeFaces LazyDataModel <t> </t>时通过JPA返回元组行列表的方法

时间:2014-11-23 16:16:11

标签: jsf jpa primefaces jsf-2.2 jpa-2.1

在某些情况下,我们需要从关联的数据模型返回元组行列表,即不是完全限定的实体,而是其中的一部分,特别是来自关联数据源的选定列的列表(可能是数据库)。

我知道一些使用JPA从数据库返回元组行列表的方法,如下所示

如果您不喜欢条件查询,则无需仔细查看JPA条件API中的代码。该问题与JPA标准没有直接关系。我更喜欢JPA标准和JPQL,因为我非常喜欢标准查询。

使用对象数组列表 - List<Object[]>

public List<Object[]> object(int first, int pageSize) {

    CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
    CriteriaQuery<Object[]>criteriaQuery=criteriaBuilder.createQuery(Object[].class);
    Root<Product> root = criteriaQuery.from(entityManager.getMetamodel().entity(Product.class));

    List<Selection<?>>selections=new ArrayList<Selection<?>>();
    selections.add(root.get(Product_.prodId));
    selections.add(root.get(Product_.prodName));
    selections.add(root.get(Product_.prodCode));
    selections.add(root.get(Product_.prodDesc));
    selections.add(root.get(Product_.marketPrice));
    selections.add(root.get(Product_.salePrice));

    criteriaQuery.select(criteriaBuilder.array(selections.toArray(new Selection[0])));
    //Or criteriaQuery.multiselect(selections.toArray(new Selection[0]));
    return entityManager.createQuery(criteriaQuery).setFirstResult(first).setMaxResults(pageSize).getResultList();
}

使用元组列表 - List<Tuple>

public List<Tuple> tuple(int first, int pageSize) {

    CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
    CriteriaQuery<Tuple>criteriaQuery=criteriaBuilder.createTupleQuery();
    Root<Product> root = criteriaQuery.from(entityManager.getMetamodel().entity(Product.class));

    List<Selection<?>>selections=new ArrayList<Selection<?>>();
    selections.add(root.get(Product_.prodId));
    selections.add(root.get(Product_.prodName));
    selections.add(root.get(Product_.prodCode));
    selections.add(root.get(Product_.prodDesc));
    selections.add(root.get(Product_.marketPrice));
    selections.add(root.get(Product_.salePrice));

    criteriaQuery.select(criteriaBuilder.tuple(selections.toArray(new Selection[0])));
    //Or criteriaQuery.multiselect(selections.toArray(new Selection[0]));
    return entityManager.createQuery(criteriaQuery).setFirstResult(first).setMaxResults(pageSize).getResultList();
}

使用映射一类对象的行列表 - List<MappedClass>

public List<ProductUtils> constructor(int first, int pageSize) {

    CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
    CriteriaQuery<ProductUtils>criteriaQuery=criteriaBuilder.createQuery(ProductUtils.class);
    Root<Product> root = criteriaQuery.from(entityManager.getMetamodel().entity(Product.class));

    List<Selection<?>>selections=new ArrayList<Selection<?>>();
    selections.add(root.get(Product_.prodId));
    selections.add(root.get(Product_.prodName));
    selections.add(root.get(Product_.prodCode));
    selections.add(root.get(Product_.prodDesc));
    selections.add(root.get(Product_.marketPrice));
    selections.add(root.get(Product_.salePrice));

    criteriaQuery.select(criteriaBuilder.construct(ProductUtils.class, selections.toArray(new Selection[0])));
    //Or criteriaQuery.multiselect(selections.toArray(new Selection[0]));
    return entityManager.createQuery(criteriaQuery).setFirstResult(first).setMaxResults(pageSize).getResultList();
}

同样可以使用JPQL重写同样的东西。

前两个是丑陋的,需要在XHTML页面上使用EL中的索引来访问属性。如果字段出现的顺序在以后更改(当然,别名可以与Tuple一起使用),则难以维护它们。此外,使用Tuple始终是可以避免的,因为它需要来自javax.persistence包的JSF中的额外依赖性,从而增加模块之间的耦合。

使用构造函数查询将结果列表映射到类可能就足够了。它可以与PrimeFaces LazyDataModel一起使用,如下所示。

@Named
@ViewScoped
public class TestManagedBean extends LazyDataModel<ProductUtils> implements Serializable {

    @Inject
    private Service service;
    private static final long serialVersionUID=1L;

    public TestManagedBean() {}

    @Override
    public List<ProductUtils> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, Object> filters) {
        // Put some logic here like setting total rows for LazyDataModel - setRowCount(10)
        return service.constructor(first, pageSize); //Use filters and sort meta whenever necessary.
    }
}

但是这也太难以维护了,如果我需要稍后在不同的地方从数据库访问更多或更少的字段,这需要创建一个新类或添加一个新的构造函数(现有类中的构造函数重载)现有的类反过来需要仔细检查构造函数方法的实际和形式参数,如果它们的数量,顺序和类型匹配,那通常会让我失明。

我希望,应该有一些更好的方法让我们能够以精确的方式解决这些问题。

现有实体类中的参数化构造函数(如果使用的话)(在这种情况下不创建像ProductUtils这样的新类)可能会在实现Web服务(JAX-WS)时导致问题申请(如果需要)。因此,我从不倾向于在任何地方使用实体类的参数化构造函数。

0 个答案:

没有答案