Получение полиморфных объектов спящего режима с использованием запроса критериев
В моей модели у меня есть абстрактный класс "Пользователь" и несколько подклассов, таких как Applicant, HiringManager и Interviewer. Они находятся в одной таблице, и у меня есть один DAO, чтобы управлять ими всеми.
Пользователь:
@Entity
@Table(name="User")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
name="role",
discriminatorType=DiscriminatorType.STRING
)
public abstract class User extends BaseObject implements Identifiable<Long> ...
HiringManager (например):
@Entity
@DiscriminatorValue("HIRING_MANAGER")
public class HiringManager extends User ...
Теперь, если бы я хотел, скажем, получить всех менеджеров по найму, которые не связаны с отделом, как мне это сделать? Я предполагаю, что это будет выглядеть примерно так:
DetachedCriteria c = DetachedCriteria.forClass(User.class);
c.add(Restrictions.eq("role", "HIRING_MANAGER"));
c.add(Restrictions.isNull("department"));
List<User> results = getHibernateTemplate().findByCriteria(c);
Но когда я запускаю это, Hibernate жалуется, что "не удалось разрешить свойство: role" (что на самом деле имеет смысл, потому что класс User действительно не имеет явного свойства role)
Итак, какой правильный способ делать то, что я пытаюсь сделать?
Ответы
Ответ 1
Возможно, мне не хватает чего-то очевидного, но поскольку вы хотите найти менеджеров по найму, почему бы вам просто не отнести подкласс HiringManager
как класс к Criteria
?
На всякий случай существует специальное свойство class
, которое можно использовать для ограничения запроса подтипом. Из справочной документации Hibernate:
...
Доступ к специальному свойству class
значение дискриминатора экземпляра в случае полиморфного упорство. Имя класса Java вложенное в предложение where будет переводится на его значение дискриминатора.
from Cat cat where cat.class = DomesticCat
Вы также можете использовать это специальное свойство класса с API-интерфейсом Criteria, но с незначительными изменениями: вы должны использовать значение дискриминатора как значение.
c.add(Restrictions.eq("class", "HIRING_MANAGER"));
В отличие от HQL, похоже, что Hibernate не выполняет перевод с API критериев. Мне не очень нравится идея использования значения дискриминатора в коде, и, возможно, еще один более чистый способ, но я не знаю об этом. Но он работает.
Ответ 2
Обратите внимание, что это также работает для сопоставлений наследования Subclass с одним оговоркой. Класс, используемый в Ограничении, должен быть конкретным классом. Если у вас есть модель типа Animal < - Mammal < - Cat, вы не можете сделать Restrictions.eq("class", Mammal.class);
и ожидать возврата всех млекопитающих. Вместо этого мне пришлось переборщить его с помощью Restrictions.or со всеми известными конкретными классами (с помощью Restrictions.in() выдается исключение класса при выполнении запроса).