Как я могу написать запрос Hibernate Criteria для суперкласса и проверить наличие определенного подкласса? - PullRequest
6 голосов
/ 02 июля 2011

Как я могу написать запрос Hibernate Criteria для суперкласса и проверить наличие определенного подкласса? Давайте представим, что у нас есть следующие классы, все сопоставленные с Hibernate-JPA:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Bar {
    @Id
    @Column(name = "id")
    private Long id;
}

@Entity
@PrimaryKeyJoinColumn(name="bar_id")
public class Foo extends Bar {
}

@Entity
@PrimaryKeyJoinColumn(name="bar_id")    
public class Goo extends Bar {
}

При написании запроса Criteria, подобного этому, я хотел бы для производительности использовать левое соединение с подклассом:

getSession()
    .createCriteria(Bar.class)
    .createAlias("Foo", "foo", CriteriaSpecification.LEFT_JOIN)
    .add(Restrictions.isNotNull("foo.bar_id"))
    .list();

Это терпит неудачу, потому что путь ассоциации "Foo", очевидно, не работает, но он проиллюстрирует то, что я хочу. Или есть другой способ сделать этот тип запроса? Мне нужно, чтобы запрос был выполнен на суперклассе. Если бы я сделал это в SQL, это выглядело бы так:

select b.*
from bar b left join foo f on f.bar_id = b.id
where f.bar_id is not null;

Вышеприведенный SQL-запрос просто для иллюстрации того, что я имею в виду. Я знаю, что в этом конкретном случае было бы проще использовать «нормальное» объединение.

1 Ответ

7 голосов
/ 02 июля 2011

Не совсем понятно, что вы хотите сделать.

Прежде всего, поскольку Foo наследуется от Bar, поиск экземпляров Bar автоматически возвращает экземпляры Foo. Hibernate заботится о присоединении к таблицам самостоятельно.

Второе: ваш SQL-запрос действительно странный. Вы делаете левое соединение (что означает, что вы ищете бары, у которых может не быть связанного с foo), но у вас также есть где close на foo.bar_id, который не равен нулю. Фактически это является внутренним соединением и может быть переписано как

select b.* from bar b inner join foo f on f.bar_id = b.id

Если вы хотите искать только Foos и только Foos, тогда используйте Критерии с Foo в качестве корневого объекта:

getSession()
    .createCriteria(Foo.class)
    .list();

Вы получите экземпляры Foo, но, поскольку Foo расширяет Bar, эти экземпляры Foo также являются экземплярами Bar. Вот что такое наследство.

Теперь, если вы создаете свой экземпляр Criteria динамически и в какой-то момент понимаете, что поиск должен возвращать только экземпляры Foo, вы должны использовать свойство неявного класса:

Criteria c = getSession().createCriteria(Bar.class, "bar")
// ...
if (limitToFoos) {
    c.add(Restrictions.eq("bar.class", Foo.class));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...