Как использовать подзапрос вместо объединенного запроса, чтобы получить правильный счетчик в спящем режиме
При условии, что у меня есть следующие две таблицы (Кошки с котятами):
==== 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;
со следующими данными
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")
Теперь я хотел бы видеть всех кошек, у которых есть котенок, чье имя содержит "котенок".
list = sess().createCriteria( Cat.class ).createAlias( "kitten", "kitten" )
.add( Restrictions.like( "kitten.name", "%kitten%" ) ).list();
Предыдущая команда не очень хороша из-за объединения, я получу повторяющиеся записи и, например, счетчик и maxresult не работают. Это хорошо документированная проблема, и упоминается использование подзапросов.
Я думаю о чем-то вроде этого (но с Criteria-Api):
from Cat where id in
(select cat_id from Kitten where name like '%kitten%')
Это не работает, потому что hibernate не дает мне доступ к "cat_id", и я не хочу делать его двунаправленным только для этого запроса.
2 ответа
Ваш запрос, если вы просто добавите проекцию, чтобы получить идентификатор кошки, является подзапросом, который вы хотели бы использовать. Так что вам просто нужно следующее:
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));
Я настоятельно рекомендую, чтобы котенок содержал ссылку на кота. Хотя для поддержания согласованности отношений как со стороны котят, так и со стороны кошек требуется немного больше внимания, но это того стоит.
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;
}
HQL должен стать таким простым, как вы хотите:
from Cat c where c in
(select parent from Kitten where name like '%kitten%')
или даже
select distinct parent from Kitten where name like '%kitten%'