JPA动态标准api查询

JPA动态标准api查询,jpa,dynamic,criteria-api,Jpa,Dynamic,Criteria Api,我想知道是否有一种通用方法可以将CriteriaAPI与更复杂的模型结合使用 我有一个实体类,它与其他实体有一对一的关系。我的服务包装器通过CriteriaAPI执行数据库查询,它从前端获取参数,以确定分页、排序和筛选 实体 @Entity public class Person implements Serializable { @Id private Long id; private String name; private String givenName;

我想知道是否有一种通用方法可以将CriteriaAPI与更复杂的模型结合使用

我有一个实体类,它与其他实体有一对一的关系。我的服务包装器通过CriteriaAPI执行数据库查询,它从前端获取参数,以确定分页、排序和筛选

实体

@Entity
public class Person implements Serializable {
    @Id
    private Long id;
    private String name;
    private String givenName;

    @Temporal(TemporalType.DATE)
    private Date birthdate;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "INFORMATION_ID")
    private Information information;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "ADDRESS_ID")
    private Address address;
    ...
}
服务

@Stateless
public class PersonService {
    @PersistenceContext(unitName = "ProblemGenericDatatableFilterPU")
    private EntityManager em;
    public List<Person> findAllPersons222(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
        CriteriaBuilder builder = em.getCriteriaBuilder();
        CriteriaQuery<Person> criteriaQuery = builder.createQuery(Person.class);
        Root<Person> rootPerson = criteriaQuery.from(Person.class);
        Join<Person, Information> joinPersonInformation = rootPerson.join(Person_.information);
        Join<Person, Address> joinPersonAddress = rootPerson.join(Person_.address);

        // select
        criteriaQuery.select(rootPerson);

        // filter
        List<Predicate> allPredicates = new ArrayList<>();
        for(Entry<String, Object> currentEntry : filters.entrySet()) {
            Predicate currentPredicate;

            if(currentEntry.getKey().startsWith("information_")) {
                currentPredicate = builder.like(
                        builder.lower(joinPersonInformation.<String>get(currentEntry.getKey())),
                    builder.lower(builder.literal(String.valueOf(currentEntry.getValue())))
                );
            }
            else if(currentEntry.getKey().startsWith("address_")) {
                currentPredicate = builder.like(
                        builder.lower(joinPersonAddress.<String>get(currentEntry.getKey())),
                    builder.lower(builder.literal(String.valueOf(currentEntry.getValue())))
                );
            }
            else {
                currentPredicate = builder.like(
                        builder.lower(rootPerson.<String>get(currentEntry.getKey())),
                    builder.lower(builder.literal(String.valueOf(currentEntry.getValue())))
                );
            }
            allPredicates.add(currentPredicate);
        }
        criteriaQuery.where(builder.and(allPredicates.toArray(new Predicate[0])));

        // order
        if(sortField != null && !sortField.isEmpty()) {
            Order orderBy;
            if(sortField.startsWith("information_")) {
                orderBy = (sortOrder == SortOrder.DESCENDING
                        ? builder.desc(joinPersonInformation.get(sortField))
                        : builder.asc(joinPersonInformation.get(sortField)));
            }
            else if(sortField.startsWith("address_")) {
                orderBy = (sortOrder == SortOrder.DESCENDING
                        ? builder.desc(joinPersonAddress.get(sortField))
                        : builder.asc(joinPersonAddress.get(sortField)));
            }
            else {
                orderBy = (sortOrder == SortOrder.DESCENDING
                        ? builder.desc(rootPerson.get(sortField))
                        : builder.asc(rootPerson.get(sortField)));
            }
            criteriaQuery.orderBy(orderBy);
        }

        Query query = em.createQuery(criteriaQuery);
        // pagination
        query.setFirstResult(first);
        query.setMaxResults(pageSize);
        return query.getResultList();
    }
}
@无状态
公共类人员服务{
@PersistenceContext(unitName=“ProblemGenericDatatableFilterPU”)
私人实体管理者;
公共列表findAllPersons222(int-first、int-pageSize、字符串排序字段、排序器排序器、映射过滤器){
CriteriaBuilder=em.getCriteriaBuilder();
CriteriaQuery CriteriaQuery=builder.createQuery(Person.class);
Root rootPerson=criteriaQuery.from(Person.class);
Join joinPersonInformation=rootPerson.Join(Person.information);
Join JoinPersonalAddress=rootPerson.Join(Person.address);
//挑选
criteriaQuery.select(rootPerson);
//滤器
List allPredicates=new ArrayList();
对于(条目currentEntry:filters.entrySet()){
谓语动词;
if(currentEntry.getKey().startsWith(“信息”){
currentPredicate=builder.like(
builder.lower(joinPersonInformation.get(currentEntry.getKey()),
builder.lower(builder.literal(String.valueOf(currentEntry.getValue()))
);
}
else if(currentEntry.getKey().startsWith(“地址”){
currentPredicate=builder.like(
builder.lower(joinPersonalAddress.get(currentEntry.getKey()),
builder.lower(builder.literal(String.valueOf(currentEntry.getValue()))
);
}
否则{
currentPredicate=builder.like(
builder.lower(rootPerson.get(currentEntry.getKey()),
builder.lower(builder.literal(String.valueOf(currentEntry.getValue()))
);
}
添加(currentPredicate);
}
其中(builder.and(allPredicates.toArray(新谓词[0]));
//命令
if(sortField!=null&&!sortField.isEmpty()){
订货人;
if(sortField.startsWith(“信息”){
orderBy=(sortOrder==sortOrder.DESCENDING)
?建造商说明(joinPersonInformation.get(sortField))
:builder.asc(joinPersonInformation.get(sortField));
}
else if(sortField.startsWith(“地址”)){
orderBy=(sortOrder==sortOrder.DESCENDING)
?生成器描述(JoinPersonalAddress.get(sortField))
:builder.asc(joinPersonalAddress.get(sortField));
}
否则{
orderBy=(sortOrder==sortOrder.DESCENDING)
?生成器描述(rootPerson.get(sortField))
:builder.asc(rootPerson.get(sortField));
}
criteriaQuery.orderBy(orderBy);
}
Query Query=em.createQuery(criteriaQuery);
//分页
query.setFirstResult(第一个);
query.setMaxResults(页面大小);
返回query.getResultList();
}
}
我需要根据访问属性的根/连接来区分过滤和排序的情况。另外,我需要在facelet中使用命名约定。除了排序之外,计数查询也是如此

现在我扪心自问,是否有一些“点符号”或任何东西使这个案例变得可有可无。在e。G原生SQL我会创建一个子查询,并从内部投影中选择所有别名值(
select*from(选择person.name作为name,选择address.street作为street,…),其中name=…和street-like…


如果有任何建议,我将不胜感激。

我终于有时间来处理我的问题了。我找到了一个不完美但对我有效的解决方案

当我搜索另一个问题时,我找到了一个非常方便的
Path-getPath(…)
方法(我还深入研究了CriteriaAPI中出色的继承关系:Path、Root、Join、From等)。考虑到这一点,我想起了我以前的问题,并想到了一种更为简练的方法。下面是我对这个的看法:

首先,我创建我需要的所有联接(即
Root
Join
),并将它们放在
Map>mapFieldToFrom=newhashmap()中;
mapFieldToFrom.put(“person”,rootPerson);
mapFieldToFrom.put(“person.address”,JoinPersonalAddress);
mapFieldToFrom.put(“person.information”,joinPersonInformation);
mapFieldToFrom.put(“person.address.information”,joinAddressInformation);
//挑选
criteriaQuery.select(rootPerson);
//滤器
List allPredicates=new ArrayList();
对于(条目currentEntry:filters.entrySet())
{
谓词currentPredicate=builder.like(
lower(getStringPath(currentEntry.getKey(),mapFieldToFrom)),
builder.lower(builder.literal(“%”+String.valueOf(currentEntry.getValue())+“%”)
);
添加(currentPredicate);
}
其中(builder.and(allPredicates.toArray(新谓词[0]));
//命令
if(sortField!=null&&!sortField.isEmpty())
{
路径实际路径=getStringPath(sortField,mapFieldToFrom);
Order orderBy=(sortOrder==sortOrder.DESCENDING)
?建造商说明(实际路径)
:builder.asc(实际路径));
criteriaQuery.orderBy(orderBy);
}
Query Query=em.createQuery(criteriaQuery);
//分页
query.setFirstResult(第一个);
query.setMaxResults(页面大小);
return query.getResultList(
@Entity
public class Address implements Serializable {
    @Id
    private Long id;
    private String street;
    private String city;
    ...
}
@Stateless
public class PersonService {
    @PersistenceContext(unitName = "ProblemGenericDatatableFilterPU")
    private EntityManager em;
    public List<Person> findAllPersons222(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
        CriteriaBuilder builder = em.getCriteriaBuilder();
        CriteriaQuery<Person> criteriaQuery = builder.createQuery(Person.class);
        Root<Person> rootPerson = criteriaQuery.from(Person.class);
        Join<Person, Information> joinPersonInformation = rootPerson.join(Person_.information);
        Join<Person, Address> joinPersonAddress = rootPerson.join(Person_.address);

        // select
        criteriaQuery.select(rootPerson);

        // filter
        List<Predicate> allPredicates = new ArrayList<>();
        for(Entry<String, Object> currentEntry : filters.entrySet()) {
            Predicate currentPredicate;

            if(currentEntry.getKey().startsWith("information_")) {
                currentPredicate = builder.like(
                        builder.lower(joinPersonInformation.<String>get(currentEntry.getKey())),
                    builder.lower(builder.literal(String.valueOf(currentEntry.getValue())))
                );
            }
            else if(currentEntry.getKey().startsWith("address_")) {
                currentPredicate = builder.like(
                        builder.lower(joinPersonAddress.<String>get(currentEntry.getKey())),
                    builder.lower(builder.literal(String.valueOf(currentEntry.getValue())))
                );
            }
            else {
                currentPredicate = builder.like(
                        builder.lower(rootPerson.<String>get(currentEntry.getKey())),
                    builder.lower(builder.literal(String.valueOf(currentEntry.getValue())))
                );
            }
            allPredicates.add(currentPredicate);
        }
        criteriaQuery.where(builder.and(allPredicates.toArray(new Predicate[0])));

        // order
        if(sortField != null && !sortField.isEmpty()) {
            Order orderBy;
            if(sortField.startsWith("information_")) {
                orderBy = (sortOrder == SortOrder.DESCENDING
                        ? builder.desc(joinPersonInformation.get(sortField))
                        : builder.asc(joinPersonInformation.get(sortField)));
            }
            else if(sortField.startsWith("address_")) {
                orderBy = (sortOrder == SortOrder.DESCENDING
                        ? builder.desc(joinPersonAddress.get(sortField))
                        : builder.asc(joinPersonAddress.get(sortField)));
            }
            else {
                orderBy = (sortOrder == SortOrder.DESCENDING
                        ? builder.desc(rootPerson.get(sortField))
                        : builder.asc(rootPerson.get(sortField)));
            }
            criteriaQuery.orderBy(orderBy);
        }

        Query query = em.createQuery(criteriaQuery);
        // pagination
        query.setFirstResult(first);
        query.setMaxResults(pageSize);
        return query.getResultList();
    }
}
public List<Person> newFindAllPersons(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters)
{
    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<Person> criteriaQuery = builder.createQuery(Person.class);

    // setting up the required joins
    Root<Person> rootPerson = criteriaQuery.from(Person.class);
    Join<Person, Information> joinPersonInformation = rootPerson.join(Person_.information);
    Join<Person, Address> joinPersonAddress = rootPerson.join(Person_.address);
    Join<Address, Information> joinAddressInformation = joinPersonAddress.join(Address_.information);

    // putting all joins into a map with a dot`ted name
    Map<String, From<?, ?>> mapFieldToFrom = new HashMap<>();
    mapFieldToFrom.put("person", rootPerson);
    mapFieldToFrom.put("person.address", joinPersonAddress);
    mapFieldToFrom.put("person.information", joinPersonInformation);
    mapFieldToFrom.put("person.address.information", joinAddressInformation);

    // select
    criteriaQuery.select(rootPerson);

    // filter
    List<Predicate> allPredicates = new ArrayList<>();
    for(Entry<String, Object> currentEntry : filters.entrySet())
    {
        Predicate currentPredicate = builder.like(
                builder.lower(getStringPath(currentEntry.getKey(), mapFieldToFrom)),
                builder.lower(builder.literal("%" + String.valueOf(currentEntry.getValue()) + "%"))
        );
        allPredicates.add(currentPredicate);
    }
    criteriaQuery.where(builder.and(allPredicates.toArray(new Predicate[0])));

    // order
    if(sortField != null && !sortField.isEmpty())
    {
        Path<?> actualPath = getStringPath(sortField, mapFieldToFrom);
        Order orderBy = (sortOrder == SortOrder.DESCENDING
                ? builder.desc(actualPath)
                : builder.asc(actualPath));

        criteriaQuery.orderBy(orderBy);
    }

    Query query = em.createQuery(criteriaQuery);
    // pagination
    query.setFirstResult(first);
    query.setMaxResults(pageSize);
    return query.getResultList();
}

/**
 * divides the given field at the last dot and takes <br>
 * -   the first part as the key in the map to retrieve the From<?, ?> <br>
 * -   the last part as the name of the column in the entity
 */
private Path<String> getStringPath(String field, Map<String, From<?, ?>> mapFieldToFrom)
{
    if(!field.matches(".+\\..+"))
    {
        throw new IllegalArgumentException("field '" + field + "' needs to be a dotted path (i. e. customer.address.city.zipcode)");
    }
    String fromPart = field.substring(0, field.lastIndexOf('.'));
    String fieldPart = field.substring(field.lastIndexOf('.') + 1);

    From<?, ?> actualFrom = mapFieldToFrom.get(fromPart);
    if(actualFrom == null)
    {
        throw new IllegalStateException("the given map does not contain a from or for the value '" + fromPart + "' or is null");
    }
    return actualFrom.get(fieldPart);
}
<p:dataTable>
    <!-- mapFieldToFrom.put("person", rootPerson); -->
    <p:column field="person.name"> 
    </p:column>

    <!-- mapFieldToFrom.put("person.address", joinPersonAddress); -->
    <p:column field="person.address.street">
    </p:column>
</p:dataTable>