Hibernate полиморфный запрос
У меня есть два класса, Персона и Компания, полученные из другого класса Контакт. Они представлены полиморфно в двух таблицах (Персона и Компания). Упрощенные классы выглядят так:
public abstract class Contact {
Integer id;
public abstract String getDisplayName();
}
public class Person extends Contact {
String firstName;
String lastName;
public String getDisplayName() {
return firstName + " " + lastName;
}
}
public class Company extends Contact {
String name;
public String getDisplayName() {
return name;
}
}
Проблема в том, что мне нужно сделать запрос, чтобы найти все контакты с displayName, содержащие определенную строку. Я не могу сделать запрос, используя displayName, потому что он не является частью ни одной из таблиц. Любые идеи о том, как сделать этот запрос?
3 ответа
Поскольку вы выполняете конкатенацию в классе Java, Hibernate не может помочь вам в этом, извините. Он может просто не видеть, что вы делаете в этом методе, поскольку на самом деле он вообще не связан с постоянством.
Решение зависит от того, как вы отобразили наследование этих классов:
Если это таблица на иерархию, вы можете использовать этот подход: напишите SQL-предложение where для запроса критерия, а затем используйте оператор case:
s.createCriteria(Contact.class)
.add(Restrictions.sqlRestriction("? = case when type='Person' then firstName || ' '|| lastName else name end"))
.list();
Если это таблица per-concrete-subclass, вам лучше написать два запроса (так как именно это и будет делать Hibernate).
Вы можете создать новый столбец в Contact
таблица, содержащая соответствующие displayName
, который вы можете заполнить через Hibernate Interceptor, чтобы он всегда содержал правильную строку автоматически.
Альтернатива будет иметь два запроса, один для Person
и один для Company
таблица, каждая из которых содержит соответствующую логику поиска. Возможно, вам придется использовать нативные запросы для поиска каскадной строки с помощью запроса LIKE (я не эксперт по HQL, хотя это вполне возможно).
Если у вас большие таблицы, вам следует подумать о полнотекстовой индексации, так как LIKE '%...%'
запросы требуют полного сканирования таблицы, если ваша база данных не поддерживает полнотекстовые индексы.
Если вы измените displayName на сопоставленное свойство (задайте для столбца имени в Company и формулу, подобную first||' '||last в Person), то можете запросить контракт, и Hibernate выполнит два запроса, оба из которых теперь имеют displayName. Вы получите список из двух списков, один из которых содержит компании, а другой содержит лиц, поэтому вам придется объединять их вместе. Я думаю, вам нужно выполнить запрос по полному имени пакета Contract или настроить typedef, чтобы сообщить об этом Hibernate.