如何在JPA中返回具有最大集合大小的对象?

时间:2014-08-29 21:18:27

标签: java jpa jpql

例如,我有这段代码:

@Entity
@Table(name = "Foo")
public class FooImpl implements Foo {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", nullable = false)
private Long id;

@Column(name = "name", nullable = false)
private String fooName;

@ElementCollection
private Set<Long> fooSet = new HashSet<Long>();

// constructors + getters

}

我想在我的服务类中创建一个方法,该方法将返回最大fooSet大小的对象。如何使用JPQL实现这一目标?以下代码不正确,但这是我尝试过的:

@Override
public Foo getTopFoo() {
return (Foo)entityManager.createQuery("select c from Foo where max(size(c.fooSet)) ").getSingleResult();
}

3 个答案:

答案 0 :(得分:2)

你可以尝试一下,因为我知道你可以在JPQL中使用/ =中的子查询,但我很怀疑它是否有效或者它是一个有效的语法(请注意使用Foo.class来避免强制转换!):

@Override
public Foo getTopFoo() {
  return entityManager.createQuery("select c from Foo c where size(c.fooSet) = (select max(size(c.fooSet)) from Foo c)", Foo.class).getSingleResult();
}

我认为你的JPA实现不会正确翻译max(size()),因为它是一个计算值:在伪SQL中,它会给出这样的结果:

select f.*, count(ff.*) as cu
from Foo f
left join Foo_fooSet ff on [...]
group by f.*

当然,您需要枚举表Foo(或f)的所有列。

您需要根据该计数返回子查询,例如:

select max(cu) from (
    select f.*, count(ff.*) as cu
    from Foo f
    left join Foo_fooSet ff on [...]
    group by f.*
)

但我不记得JPQL允许from接受子查询。

但是,您可以使用本机查询,这可以工作:

select f.*
from Foo f
left join Foo_fooSet ff on [...]
group by f.*
having count(ff.*) = (
  select max(cu) from (
    select f.id, count(ff.*) as cu
    from Foo f
      left join Foo_fooSet ff on [...]
    group by f.id
  )
)

在子查询(计数)中,您只需要id。

如果是第一个select(f。*),则必须将所有列对应于实体的字段。玩得开心!

或:返回实体的ID,然后使用entityManager加载它们。

答案 1 :(得分:0)

最简单,最易读的方法是使用两个查询。

select id, count(*) from Bar group by id order by count(*) desc, id asc

此查询将为您提供ID和集合大小(假设Bar是集合表的名称。

使用JPA,您可以轻松select only the first result。使用该ID,选择Foo对象很容易。

另一种选择是在SQL中限制结果并与Foo表连接。

from Foo where id = (select top 1 id from (select id, count(*) from Bar group by id, order by count(*) desc, id asc))

然而,这不能以db不可知的方式完成。

答案 2 :(得分:0)

您似乎走在正确的轨道上,只需要子查询返回最大值并将其与当前c列表的大小进行比较。类似的东西:

因此,如果"Select max(size(c.fooSet)) from Foo c"为您提供最大值,

"select f from Foo f where size(f.fooSet) = (select max(size(c.fooSet)) from Foo c)"

应该为您提供尺寸等于最大尺寸的Foos。