【发布时间】:2015-10-22 19:09:59
【问题描述】:
我想知道是否有一种通用的方法可以将标准 api 与更复杂的模型结合使用?
我有一个与其他实体具有一对一关系的实体类。我通过条件 api 进行数据库查询的服务包装器从前端获取参数以计算分页、排序和过滤。
实体
@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;
...
}
@Entity
public class Information implements Serializable {
@Id
private Long id;
private String detail;
...
}
@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();
}
}
我需要根据我访问属性的根/连接来区分过滤和排序的情况。另外,我需要在 facelet 中使用命名约定。除了排序之外,count-查询也是如此。
现在我问自己是否有一些“点符号”或任何使案例可有可无的东西。在 e。 G。本机 SQL 我会做一些事情,比如创建一个子查询并从内部投影中选择所有别名值 (select * from (select person.name as name, address.street as street, ...) where name = ... and street like ...)。
如果有任何建议,我将不胜感激。
【问题讨论】:
-
嗨@bhdrkn,感谢您的提示。我喜欢你的
SimpleSelectBuilder,并且会更深入地了解。但恐怕它不能解决我的问题。您只有一个root字段,每个谓词都使用该字段。由于我的关系问题,我需要在Root和各种动态Join对象上构建谓词,这些对象由字段名称定义。 -
嗨,Filou 在 SimpleSelectBuilder 中有一个支持深度连接的方法。但它不支持内部选择。也许您可以添加它们以供自己使用。
-
嗨,bhdrkn,我对这些方法进行了更深入的研究。它们确实节省了很多样板文件,但最终在使用
SimpleSelectBuilder时,您需要了解在哪个连接中定义了哪个字段的元信息。您不能遍历参数-Map<String, Object>并将每个字符串都视为相同。尽管如此,我仍然喜欢您的 Builder :-) 并且可能会根据我的需要编写一些内容。非常感谢! -
如果您写了一些量身定制的内容,请务必将其发布为答案
标签: jpa dynamic criteria-api