Упорядочивание результатов запроса Hibernate Criteria с использованием информации о дочерних объектах запрашиваемых - PullRequest
4 голосов
/ 10 апреля 2010

У меня есть две сущности: Человек и Книга. В системе хранится только один экземпляр конкретной книги (при добавлении книги приложение проверяет, найдена ли эта книга, прежде чем добавлять новую строку в базу данных). Соответствующий исходный код сущностей можно найти ниже:

@Entity
@Table(name="persons")
@SequenceGenerator(name="id_sequence", sequenceName="hibernate_sequence")
public class Person extends BaseModel
{
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_sequence")
    private Long id = null;

    @ManyToMany(targetEntity=Book.class)
    @JoinTable(name="persons_books", joinColumns = @JoinColumn( name="person_id"), inverseJoinColumns = @JoinColumn( name="book_id"))
    private List<Book> ownedBooks = new ArrayList<Book>();
}

@Entity
@Table(name="books")
@SequenceGenerator(name="id_sequence", sequenceName="hibernate_sequence")
public class Book extends BaseModel
{
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_sequence")
    private Long id = null;

    @Column(name="name")
    private String name = null;
}

Моя проблема в том, что я хочу найти людей, которые владеют некоторыми книгами, принадлежащими конкретному человеку. Возвращаемый список людей должен быть упорядочен с использованием следующей логики: лицо, владеющее большинством одинаковых книг, должно находиться на первом месте в списке, второе лицо в списке не имеет столько книг, сколько первое лицо, но больше третий человек. Код метода, выполняющего этот запрос, добавлен ниже:

@Override
public List<Person> searchPersonsWithSimilarBooks(Long[] bookIds) {
    Criteria similarPersonCriteria = this.getSession().createCriteria(Person.class);
    similarPersonCriteria.add(Restrictions.in("ownedBooks.id", bookIds));

    //How to set the ordering?
    similarPersonCriteria.addOrder(null);

    return similarPersonCriteria.list();
}

Мой вопрос заключается в том, что это можно сделать с помощью Hibernate? И если да, то как это можно сделать? Я знаю, что мог бы реализовать Comparator, но я бы предпочел использовать Hibernate для решения этой проблемы.

При использовании SQL желаемый результат может быть достигнут с помощью следующего запроса SQL:

select p.name, count(p.name) as bookCount from persons p, books b, person_book pb
where pb.person_id = p.id and pb.book_id = b.id and b.id in (1,2,3,4,5,6) group by
name order by bookCount desc 

Я пытался выяснить, как перевести это в запрос критерия. Я пытался использовать проекции, но я не могу отобразить результаты обратно на объект Person.

Ответы [ 2 ]

2 голосов
/ 11 апреля 2010
1 голос
/ 11 апреля 2010

Мне наконец удалось решить эту проблему. Следующий метод работает как ожидалось:

@Override
public List<Person> searchPersonsWithSimilarBooks(Long[] bookIds) {
    Criteria similarPersonCriteria = this.getSession().createCriteria(Person.class, "p");

    Criteria bookCriteria = similarPersonCriteria.createCriteria("ownedBooks", "b");
    bookCriteria.add(Restrictions.in("b.id", bookIds));

    similarPersonCriteria.setProjection(Projections.projectionList()
            .add(Projections.groupProperty("p.id"), "id")
            .add(Projections.rowCount(), "similarBookCount"));

    similarPersonCriteria.addOrder(Order.desc("similarBookCount"));
    similarPersonCriteria.setResultTransformer(new AliasToBeanResultTransformer(Person.class));

    return similarPersonCriteria.list();
}

Я также обновил свой класс person, добавив временное свойство с именем SimilarBookCount , которое может быть полезно в некоторых ситуациях.

...