Можно ли запрашивать объекты JPA с помощью ElementCollections, где ElementCollection содержит все элементы в заданном наборе элементов?

Как использовать JPQL для запроса объектов JPA с помощью ElementCollections, где ElementCollection содержит все элементы в заданном наборе элементов?

Например, если объект Node определяет ElementCollection «атрибутов».

@ElementCollection(fetch=FetchType.EAGER)
@CollectionTable(name="node_attributes", joinColumns=@JoinColumn(name="node_name"))
@MapKeyColumn(name="name")
@Column(name="value")
Map<String, String> attributes = new HashMap<String, String>();

Я хотел бы найти все объекты Node, которые имеют набор заданных атрибутов. Я пробовал следующее, надеясь, что «ЧЛЕН» поддерживает коллекции.

"SELECT n FROM Node n WHERE :attributes MEMBER OF n.attributes"

Этот запрос всегда возвращает пустой список. Возможен ли простой запрос JPQL для этого варианта использования?


person dbschofield    schedule 24.04.2015    source источник


Ответы (1)


Из спецификации JPA 2.0, глава 4.4.4 Выражения пути:

Идентификационная переменная, за которой следует оператор навигации (.) и поле состояния или поле ассоциации, представляет собой выражение пути. Тип выражения пути — это тип, вычисленный в результате навигации; то есть тип поля состояния или поля ассоциации, к которому переходит выражение.

Идентификационная переменная, определяемая оператором KEY, VALUE или ENTRY, является выражением пути. Операторы KEY, VALUE и ENTRY могут применяться только к идентификационным переменным, которые соответствуют ассоциациям со значением карты или коллекциям элементов со значением карты.

Выражение пути, использующее оператор ENTRY, является терминальным. Он не может быть дополнительно составлен и может отображаться только в списке SELECT запроса.

Так много для теории. Что касается вопроса, я вижу три немного разных ответа в зависимости от того, хотите ли вы искать по Map.Key, Map.Value или Map.Entry:

String qlKeys = "SELECT DISTINCT n " +
                "FROM Node n JOIN n.attributes a " +
                "WHERE KEY(a) IN :keys";
List<Node> nodes = em.createQuery(qlKeys, Node.class)
                     .setParameter("keys", Arrays.asList("foo", "bar"))
                     .getResultList();
String qlValues = "SELECT DISTINCT n " +
                  "FROM Node n JOIN n.attributes a " +
                  "WHERE VALUE(a) IN :values";
List<Node> nodes = em.createQuery(qlValues, Node.class)
                     .setParameter("values", Arrays.asList("baz", "qux"))
                     .getResultList();

Имея в виду, что оператор ENTRY может появляться только в предложении SELECT, нам, возможно, придется заменить его сочетанием операторов KEY и VALUE, т.е.

SELECT DISTINCT n 
FROM Node n JOIN n.attributes a
WHERE KEY(a) IN :keys AND VALUE(a) IN :values

В приведенных выше примерах:

  • переменная идентификации представлена ​​c
  • выражение пути представлено c.attributes
  • поле связи представлено a
person wypieprz    schedule 28.04.2015