Спящий полиморфный запрос - PullRequest
6 голосов
/ 12 июня 2009

У меня есть два класса, Person и Company, производные от другого класса Contact. Они представлены полиморфно в двух таблицах (Персона и Компания). Упрощенные классы выглядят так:

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 ]

4 голосов
/ 12 июня 2009

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

Решение зависит от того, как вы отобразили наследование этих классов:

Если это таблица на иерархию, вы можете использовать этот подход: написать предложение SQL where для запроса критерия, а затем использовать оператор case:

s.createCriteria(Contact.class)
 .add(Restrictions.sqlRestriction("? = case when type='Person' then firstName || ' '|| lastName else name end"))
 .list();

Если это таблица для каждого конкретного подкласса, то вам лучше написать два запроса (так как именно это будет делать Hibernate в любом случае).

2 голосов
/ 12 июня 2009

Вы можете создать новый столбец в таблице Contact, содержащий соответствующий displayName, который вы можете заполнить с помощью Hibernate Interceptor , чтобы он всегда содержал правильную строку автоматически.

Альтернативой могут быть два запроса: один для Person и один для таблицы Company, каждый из которых содержит соответствующую логику поиска. Возможно, вам придется использовать нативные запросы для поиска каскадной строки с помощью LIKE-запроса (хотя я не эксперт по HQL, но это вполне возможно).

Если у вас большие таблицы, вам следует подумать о полнотекстовой индексации, поскольку LIKE '%...%' запросы требуют полного сканирования таблиц, если ваша база данных не поддерживает полнотекстовые индексы.

1 голос
/ 12 июня 2009

Если вы измените displayName на сопоставленное свойство (задайте для столбца имени в Company и для формулы, например first || '' || last in Person), тогда запрос может выполнить запрос Contract, и Hibernate выполнит два запроса, оба из которые теперь имеют displayName. Вы получите список из двух списков, один из которых содержит компании, а другой содержит людей, поэтому вам придется объединять их вместе. Я думаю, вам нужно выполнить запрос по полному имени пакета Contract или настроить typedef, чтобы сообщить об этом Hibernate.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...