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.

Другие вопросы по тегам