Использовать критерии гибернации для фильтрации ключей и значений в Map
У меня есть следующий сохраненный класс:
public class Code {
@ElementCollection(targetClass = CodeValue.class)
@MapKeyClass(CodeProperty.class)
@JoinTable(name="code_properties")
@CreateIfNull( value = false )
private Map<CodeProperty,CodeValue> propertiesMap =
new HashMap<CodeProperty, CodeValue>();
...
}
public class CodeProperty {
private String name;
...
}
public class CodeValue {
private String value;
...
}
И я пытаюсь получить список кода, отфильтрованный некоторыми свойствами, которые у меня есть в propertiesMap (например, коды, где свойство с именем "color" имеет значение "зеленый".
Я использую следующие базовые критерии:
Criteria criteria = currentSession()
.createCriteria(Code.class, "code")
.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
Когда я пытаюсь выполнить фильтр коллекции (как предложено здесь):
criteria.createAlias("code.properties", "p");
criteria.add(Restrictions.eq("p.foo", "test1"));
criteria.setFetchMode("code.properties", FetchMode.JOIN);
criteria.list();
Я получаю следующую ошибку:
org.hibernate.QueryException: could not resolve property: foo of: com.example.CodeValue
Это означает, что я действительно не понимаю, почему, hibernate считает, что code.properties является CodeValue вместо карты!!!
Я также попытался получить доступ к этому полю, не создавая псевдоним, и таким образом hibernate, похоже, обращается к правильному классу Code. Я использовал properties.indeces (как предложено здесь):
criteria.add(Restrictions.eq("properties.indeces", "foo"));
criteria.list();
Но с этим я получаю следующую ошибку:
could not resolve property: properties.indeces of: com.example.Code
Может кто-нибудь помочь мне понять, что случилось? Каким будет правильный запрос критериев, чтобы найти коды с зеленым цветом?
Вы можете проверить проект Github, демонстрирующий эту проблему.
Спасибо
Ответы
Ответ 1
Я не думаю, что вы можете сделать это с помощью устаревшего API-интерфейсов Hibernate и существует небольшое ограничение с внедрением Hibernate с использованием API-критериев JPA. Один из способов решить эту проблему:
Получите List<CodeProperty>
, запросив этот объект непосредственно с вашими требованиями к предикату.
List<CodeProperty> propertyKeys = entityManager
.createQuery( "FROM CodeProperty p WHERE p.name = :name" )
.setParameter( "name", "foo" )
.getResultList();
Запросите свой объект Code
, используя критерии JPA.
// setup the query
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Code> query = cb.createQuery( Code.class );
Root<Code> root = query.from( Code.class );
MapJoin<Code, CodeProperty, CodeValue> mapRoot = root.joinMap( "propertiesMap" );
query.select( root ).where( mapRoot.key().in( propertyKeys ) );
// get results
List<Code> results = entityManager.createQuery( query ).getResultList();
Я попытался объединить их, используя:
query
.select( root )
.where ( cb.eq( mapRoot.key().get( "name" ), "foo" ) )
Проблема заключается в том, что это приводит к исключению NotYetImplemented
: (.
Ответ 2
Возможно, это не то, что вы ожидаете, но в более высокой версии спящего режима псевдоним не будет разрешен. У меня возникла проблема в Projections при использовании псевдонима
https://stackoverflow.com/questions/36607042/hibernate-criteria-query-using-projections-aggregate-function-alias-throws-sette
Ответ 3
Пожалуйста, подтвердите, используете ли вы индексы или индексы. Правильное использование выглядит следующим образом:
criteria.createAlias("code.properties", "p");
criteria.add(Restrictions.eq("p.indices", "foo"));
criteria.list();
В качестве альтернативы вы можете использовать
eq("p." + CollectionPropertyNames.COLLECTION_INDICES)
в Ограничении.
Пожалуйста, дайте мне знать, если он все еще не работает для вас.
Ответ 4
Существуют различные проблемы с вашим подходом:
Просмотр папки MapTest в вашем проекте github Я могу посоветовать вам всегда вызывать имена переменных как имена столбцов и использовать те же имена в критериях.
Критерии - это карты, первым аргументом которых является имя атрибута, а второй аргумент - значение атрибута.
Для многих-многих отношений вы можете попробовать:
@JoinTable(
name="docente_classe",
joinColumns=
@JoinColumn(name="id_dipendente", referencedColumnName="id_dipendente"),
inverseJoinColumns=
@JoinColumn(name="id_classe", referencedColumnName="id_classe")
)
Это аннотация JPA, я не знаю, компилируется ли этот проект.
https://github.com/tredue1/School_Manager/blob/master/code/SM/src/main/java/agc2/it/sm/gestioneDocente/DocenteJpa.java
Для запроса по многим отношениям смотрите этот пост:
jpa критерии для многих и многих отношений.