如何使用JPA Criteria API编写此查询?

huangapple go评论101阅读模式
英文:

how to write this query using jpa criteria api?

问题

  1. 选择 c.id
  2. (选择 c2.value customer_table c2 其中 c2.id = c.id c2.key = 'test') 作为 "test"
  3. (选择 c2.value customer_table c2 其中 c2.id = c.id c2.key = 'service-category') 作为 "service-category"
  4. (选择 c2.value customer_table c2 其中 c2.id = c.id c2.key = 'exam') 作为 "exam"
  5. customer_table c
  6. 分组 c.id;
英文:
  1. Select c.id,
  2. (Select c2.value from customer_table c2 Where c2.id = c.id And c2.key = 'test') as "test",
  3. (Select c2.value from customer_table c2 Where c2.id = c.id And c2.key = 'service-category') as "service-category",
  4. (Select c2.value from customer_table c2 Where c2.id = c.id And c2.key = 'exam') as "exam"
  5. From customer_table c
  6. Group By c.id;

答案1

得分: 3

假设客户表实体 customerTable 的存在和正确建模,其关系以及 value 是 String 类型,实现如下所示:

  1. CriteriaBuilder cb = entityManager.getCriteriaBuilder();
  2. CriteriaQuery<YourPojo> cq = cb.createQuery(YourPojo.class);
  3. Root<CustomerTable> root = cq.from(CustomerTable.class);
  4. // 子查询 1
  5. Subquery<String> sqVal1 = cq.subquery(String.class);
  6. Root<CustomerTable> sq1Root = sqVal1.from(CustomerTable.class);
  7. sqVal1.where(
  8. cb.and(
  9. cb.equal(root.get("id"), sq1Root.get("id")),
  10. cb.equal(sq1Root.get("key"), "test")
  11. )
  12. );
  13. sqVal1.select(sq1Root.get("value"));
  14. // 子查询 2
  15. Subquery<String> sqVal2 = cq.subquery(String.class);
  16. Root<CustomerTable> sq2Root = sqVal2.from(CustomerTable.class);
  17. sqVal2.where(
  18. cb.and(
  19. cb.equal(root.get("id"), sq2Root.get("id")),
  20. cb.equal(sq2Root.get("key"), "service-category")
  21. )
  22. );
  23. sqVal2.select(sq2Root.get("value"));
  24. // 子查询 3
  25. Subquery<String> sqVal3 = cq.subquery(String.class);
  26. Root<CustomerTable> sq3Root = sqVal3.from(CustomerTable.class);
  27. sqVal3.where(
  28. cb.and(
  29. cb.equal(root.get("id"), sq3Root.get("id")),
  30. cb.equal(sq3Root.get("key"), "exam")
  31. )
  32. );
  33. sqVal3.select(sq3Root.get("value"));
  34. cq.groupBy(root.get("id"));
  35. cq.multiselect(
  36. root.get("id"),
  37. sqVal1.getSelection(),
  38. sqVal2.getSelection(),
  39. sqVal3.getSelection()
  40. );

你需要一个带有与 multiselect 子句中参数相同(顺序和类型相同)的构造函数的 POJO(普通 Java 对象)。

  1. public class YourPojo {
  2. public YourPojo(String id, String val1, String val2, String val3){
  3. // 构造函数实现部分
  4. }
  5. }

推荐使用元模型来访问实体的属性,这将会替换下面的代码:

  1. root.get("id");

使用以下代码:

  1. root.get(CustomerTable_.id);

使用元模型的众多优势之一是能够自动补全属性名称,并降低此处出错的机会。

英文:

Assuming the existence and correct modeling of the customerTable entity, its relationships and that value is of type String, the implementation would be like this:

  1. CriteriaBuilder cb = entityManager.getCriteriaBuilder();
  2. CriteriaQuery&lt;YourPojo&gt; cq = cb.createQuery(YourPojo.class);
  3. Root&lt;CustomerTable&gt; root = cq.from(CustomerTable.class);
  4. //Subquery 1
  5. Subquery&lt;String&gt; sqVal1 = cq.subquery(String.class);
  6. Root&lt;CustomerTable&gt; sq1Root = sqVal1.from(CustomerTable.class);
  7. sqVal1.where(
  8. cb.and(
  9. cb.equal(root.get(&quot;id&quot;),sq1Root.get(&quot;id&quot;)),
  10. cb.equal(sq1Root.get(&quot;key&quot;),&quot;test&quot;)
  11. )
  12. );
  13. sqVal1.select(sq1Root.get(&quot;value&quot;));
  14. //Subquery 2
  15. Subquery&lt;String&gt; sqVal2 = cq.subquery(String.class);
  16. Root&lt;CustomerTable&gt; sq2Root = sqVal2.from(CustomerTable.class);
  17. sqVal2.where(
  18. cb.and(
  19. cb.equal(root.get(&quot;id&quot;),sq2Root.get(&quot;id&quot;)),
  20. cb.equal(sq2Root.get(&quot;key&quot;),&quot;service-category&quot;)
  21. )
  22. );
  23. sqVal2.select(sq2Root.get(&quot;value&quot;));
  24. //Subquery 3
  25. Subquery&lt;String&gt; sqVal3 = cq.subquery(String.class);
  26. Root&lt;CustomerTable&gt; sq3Root = sqVal3.from(CustomerTable.class);
  27. sqVal3.where(
  28. cb.and(
  29. cb.equal(root.get(&quot;id&quot;),sq3Root.get(&quot;id&quot;)),
  30. cb.equal(sq3Root.get(&quot;key&quot;),&quot;exam&quot;)
  31. )
  32. );
  33. sqVal3.select(sq3Root.get(&quot;value&quot;));
  34. cq.groupBy(root.get(&quot;id&quot;));
  35. cq.multiselect(
  36. root.get(&quot;id&quot;),
  37. sqVal1.getSelection(),
  38. sqVal2.getSelection(),
  39. sqVal3.getSelection()
  40. );

You need a pojo with a constructor with the same parameters (in order and type) as the multiselect clause

  1. public class YourPojo {
  2. public YourPojo(String id, String val1, String val2, String val3){
  3. [...]
  4. }
  5. }

It is recommended to use metamodels to access the properties of the entities, which would lead to replace the following code

  1. root.get(&quot;id&quot;);

with this other

  1. root.get(CustomerTable_.id);

One of the many advantages of using metamodels without getting too into the subject is the ability to auto-complete the property name and reduce the chance of error at this point.

huangapple
  • 本文由 发表于 2020年8月28日 07:16:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/63625350.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定