How to use a subquery instead of a joined query to get correct count with hibernate

落花浮王杯 提交于 2019-12-14 03:59:35

问题


assuming I have following two tables (Cats with Kittens):

==== Cat.java ====
@Id @GeneratedValue( strategy = GenerationType.IDENTITY ) 
private long id;

@Column( unique = true, nullable = false )
private String name;

@OneToMany @JoinColumn( name = "cat_id" )
private List<Kitten> kitten;

==== Kitten.java ====
@Id @GeneratedValue( strategy = GenerationType.IDENTITY ) 
private long id;

@Column( unique = true, nullable = false )
private String name;

with the following data

Cat(id, name)
Cat(1, "Cat 1")
Cat(2, "Cat 2")

Kitten(id, cat_id, name)
Kitten(1, 1, "Kitten 1")
Kitten(2, 1, "Kitten 2")
Kitten(3, 2, "Kitten 3")
Kitten(3, 2, "Bad Kit")

Now I would like to see all cats which have a kitten whose name contains "kitten".

list = sess().createCriteria( Cat.class ).createAlias( "kitten", "kitten" )
.add( Restrictions.like( "kitten.name", "%kitten%" ) ).list();

The previous command is not very nice because of the join I will get duplicate entries and for example count and maxresult are not working. This is a well documented problem and it is mentioned to use subqueries instead.

I'm thinking of something like this (but with Criteria-Api):

from Cat where id in
(select cat_id from Kitten where name like '%kitten%')

This doesn't work because hibernate doesn't give me access to "cat_id" and I don't want to make it bidirectional just for this query.


回答1:


Your query, if you just add a projection to get the cat ID, is the subquery you'd like to use. So you just need the following:

DetachedCriteria acceptedCatIds = DetachedCriteria.forClass(Cat.class);
acceptedCatIds.createAlias("kitten", "kitten")
              .add(Restrictions.like("kitten.name", "%kitten%" ))
              .setProjection(Projections.id());

Criteria acceptedCats = session.createCriteria(Cat.class)
acceptedCats.add(Subqueries.propertyIn("id", acceptedCatIds));



回答2:


I would strongly recommend you to have Kitten containing reference to Cat too. Though there is a bit more attention needed to keep the relationship consistent from both Kitten and Cat side, but it worth.

class Cat {

    @Id @GeneratedValue( strategy = GenerationType.IDENTITY ) 
    private long id;

    @OneToMany(mappedBy="parent")
    private List<Kitten> kitten;
}

class Kitten {

    @Id @GeneratedValue( strategy = GenerationType.IDENTITY ) 
    private long id;

    @Column( unique = true, nullable = false )
    private String name;

    @ManyToOne
    @JoinColumn( name = "cat_id" )
    private Cat parent;
}

The HQL should become as simple as what you want:

from Cat c where c in
(select parent from Kitten where name like '%kitten%')

or even

select distinct parent from Kitten where name like '%kitten%'


来源:https://stackoverflow.com/questions/18815730/how-to-use-a-subquery-instead-of-a-joined-query-to-get-correct-count-with-hibern

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!