Получение полиморфных объектов гибернации с помощью запроса критериев
В моей модели у меня есть абстрактный класс "Пользователь" и несколько подклассов, таких как 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 жалуется, что "не удалось разрешить свойство: роль" (что на самом деле имеет смысл, потому что класс User действительно не имеет явного свойства роли)
Так как правильно делать то, что я пытаюсь сделать?
2 ответа
Я могу упустить что-то очевидное, но, так как вы хотите найти менеджеров по найму, почему бы вам просто не передать HiringManager
подкласс как класс к Criteria
?
На всякий случай есть специальный class
свойство, которое вы можете использовать, чтобы ограничить запрос подтипом. Из справочной документации Hibernate:
14,9. Пункт где
...
Особая собственность
class
обращается к значению дискриминатора экземпляра в случае полиморфной персистентности. Имя класса Java, встроенное в предложение where, будет преобразовано в его значение дискриминатора.from Cat cat where cat.class = DomesticCat
Вы также можете использовать это специальное свойство класса с Criteria API, но с небольшим изменением: вы должны использовать значение дискриминатора в качестве значения.
c.add(Restrictions.eq("class", "HIRING_MANAGER"));
В отличие от HQL, похоже, что Hibernate не выполняет перевод с помощью Criteria API. Мне не очень нравится идея использования значения дискриминатора в коде, и, возможно, есть другой более чистый способ, но я не знаю об этом. Но это работает.
Обратите внимание, что это также работает для отображений наследования Joined Subclass с одним предупреждением. Класс, используемый в Ограничении, должен быть конкретным классом. Если у вас есть модель, такая как Animal <- Mammal <- Cat, вы не можете сделать Restrictions.eq("class", Mammal.class);
и ожидать, чтобы вернуть всех млекопитающих. Вместо этого мне пришлось грубо заставить его использовать Restrictions.or со всеми известными конкретными классами (использование Restrictions.in() дало исключение приведения класса при выполнении запроса).