Интересно, есть ли общий способ использования 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();
}
}
Мне нужно сделать различие случаев для фильтрации и сортировки в зависимости от корня / соединения, по которому я обращаюсь к свойству. Кроме того, мне нужно использовать соглашение об именах в фейсплете. То же самое касается запроса count, за исключением сортировки.
Теперь я спрашиваю себя, есть ли какие-нибудь «точечные обозначения» или что-то еще, что делает случай необязательным. В e. грамм. собственный SQL. Я бы сделал что-то вроде подзапроса и выбрал бы все значения псевдонимов из внутренней проекции (select * from (select person.name as name, address.street as street, ...) where name = ... and street like ...
).
Буду признателен за любой совет.
SimpleSelectBuilder
, и я посмотрю на него поближе. Но боюсь, это не решит мою проблему. У вас есть только одно полеroot
, которое используется каждым предикатом. С моей проблемой отношений мне нужно построить предикаты дляRoot
и различных динамическихJoin
объектов, которые определяются именем поля. - person Filou   schedule 31.07.2015SimpleSelectBuilder
вам нужно иметь метаинформацию, какое поле определено в каком соединении. Вы не можете перебирать параметр-Map<String, Object>
и обрабатывать каждую строку одинаково. Тем не менее, мне все еще нравится ваш Builder :-) и, наверное, напишу что-нибудь под мои нужды. Большое спасибо! - person Filou   schedule 31.07.2015