Вопрос

Какие альтернативы у меня есть для реализации запроса на объединение с использованием спящего режима?Я знаю, что hibernate на данный момент не поддерживает запросы на объединение, сейчас единственный способ создать объединение, который я вижу, - это использовать таблицу представления.

Другой вариант — использовать простой jdbc, но таким образом я потеряю все полезные запросы примеров/критериев, а также проверку сопоставления спящего режима, которую спящий режим выполняет для таблиц/столбцов.

Это было полезно?

Решение

Используйте ПРОСМОТР.Одни и те же классы могут быть сопоставлены с разными таблицами/представлениями, используя имя сущности, поэтому у вас даже не будет большого дублирования.Быть там, сделать это, работает нормально.

У обычного JDBC есть еще одна скрытая проблема:он не знает о кеше сеанса Hibernate, поэтому, если что-то было кэшировано до конца транзакции и не было удалено из сеанса Hibernate, запрос JDBC не найдет это.Иногда это может быть очень загадочно.

Другие советы

Вы могли бы использовать id in (select id from ...) or id in (select id from ...)

напримервместо нерабочий

from Person p where p.name="Joe"
union
from Person p join p.children c where c.name="Joe"

ты мог бы сделать

from Person p 
  where p.id in (select p1.id from Person p1 where p1.name="Joe") 
    or p.id in (select p2.id from Person p2 join p2.children c where c.name="Joe");

По крайней мере, используя MySQL, вы позже столкнетесь с проблемами производительности.Иногда вместо этого проще выполнить соединение бедняка по двум запросам:

// use set for uniqueness
Set<Person> people = new HashSet<Person>((List<Person>) query1.list());
people.addAll((List<Person>) query2.list());
return new ArrayList<Person>(people);

Зачастую лучше выполнить два простых запроса, чем один сложный.

РЕДАКТИРОВАТЬ:

в качестве примера приведем вывод EXPLAIN результирующего запроса MySQL из решения подвыбора:

mysql> explain 
  select p.* from PERSON p 
    where p.id in (select p1.id from PERSON p1 where p1.name = "Joe") 
      or p.id in (select p2.id from PERSON p2 
        join CHILDREN c on p2.id = c.parent where c.name="Joe") \G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: a
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 247554
        Extra: Using where
*************************** 2. row ***************************
           id: 3
  select_type: DEPENDENT SUBQUERY
        table: NULL
         type: NULL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
        Extra: Impossible WHERE noticed after reading const tables
*************************** 3. row ***************************
           id: 2
  select_type: DEPENDENT SUBQUERY
        table: a1
         type: unique_subquery
possible_keys: PRIMARY,name,sortname
          key: PRIMARY
      key_len: 4
          ref: func
         rows: 1
        Extra: Using where
3 rows in set (0.00 sec)

Самое главное: 1.row не использует индекс и учитывает более 200 тыс. строк.Плохой!Выполнение этого запроса заняло 0,7 секунды, тогда как оба подзапроса выполняются за миллисекунды.

Я вынужден согласиться с Владимиром.Я тоже рассматривал возможность использования UNION в HQL и не смог найти обходного пути.Странно было то, что я мог обнаружить (в FAQ по Hibernate), что UNION не поддерживается, отчеты об ошибках, относящиеся к UNION, помечены как «исправленные», группы новостей людей, говорящих, что утверждения будут сокращены в UNION, и другие группы новостей людей, сообщающих, что он работает. отлично...После целого дня возни с этим я в конечном итоге перенес свой HQL обратно на простой SQL, но сделать это в представлении в базе данных было бы хорошим вариантом.В моем случае части запроса генерировались динамически, поэтому вместо этого мне пришлось встроить SQL в код.

У меня есть решение для одного критического сценария (с которым я много боролся) с объединением в HQL.

напримерВместо того, чтобы не работать: -

select i , j from A a  , (select i , j from B union select i , j from C) d where a.i = d.i 

ИЛИ

select i , j from A a  JOIN (select i , j from B union select i , j from C) d on a.i = d.i 

ВЫ могли бы сделать это в Hibernate HQL ->

Query q1 =session.createQuery(select i , j from A a JOIN B b on a.i = b.i)
List l1 = q1.list();

Query q2 = session.createQuery(select i , j from A a JOIN C b on a.i = b.i)
List l2 = q2.list();

тогда вы можете добавить оба списка ->

l1.addAll(l2);

Представление — лучший подход, но поскольку hql обычно возвращает список или набор...вы можете сделать list_1.addAll(list_2).Полный отстой по сравнению с профсоюзом, но должно работать.

Возможно, мне нужно было решить более простую задачу.Мой «например» был в JPA с Hibernate в качестве поставщика JPA.

Я разделил три выбора (два во втором случае) на множественный выбор и объединил возвращенные коллекции, эффективно заменив «объединить все».

Я тоже прошел через эту боль - если запрос генерируется динамически (например.Критерии гибернации), то я не смог найти практического способа сделать это.

Хорошей новостью для меня было то, что я исследовал объединение только для решения проблем с производительностью при использовании оператора «или» в базе данных Oracle.

Решение, опубликованное Патриком (программное объединение результатов с использованием набора), хотя и было уродливым (тем более, что я также хотел выполнить разбивку результатов по страницам), было для меня адекватным.



Как сказал Патрик, добавив СПИСОКс каждого ВЫБИРАТЬ было бы хорошей идеей, но помните, что это действует как СОЮЗ ВСЕХ.Чтобы избежать этого побочного эффекта, просто контролируйте, добавлен ли объект уже в окончательную коллекцию или нет.Если нет, то добавьте его.
Еще кое-что, о чем вам следует позаботиться, это то, что если у вас есть какие-либо ПРИСОЕДИНИТЬСЯ в каждом ВЫБИРАТЬ, результатом будет список массива объектов(List<Objetc[]>), поэтому вам придется перебирать его, чтобы сохранить только тот объект, который вам нужен.

Надеюсь, что это работает.

Это особый случай, но он может вдохновить вас на создание собственного решения.Цель здесь — подсчитать общее количество записей из двух разных таблиц, где записи соответствуют определенным критериям.Я считаю, что этот метод подойдет для любого случая, когда вам нужно агрегировать данные из нескольких таблиц/источников.

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

QueryParms parms=new QueryParms();
parms.put("PROCDATE",PROCDATE);

Long pixelAll = ((SourceCount)Fetch.row("PIXEL_ALL",parms,logger)).getCOUNT();

Как вы можете видеть здесь, именованный запрос начинает очень сильно напоминать оператор объединения:

@Entity
@NamedQueries({
        @NamedQuery(
            name  ="PIXEL_ALL",
            query = "" +
                    "  SELECT new SourceCount(" +
                    "     (select count(a) from PIXEL_LOG_CURR1 a " +
                    "       where to_char(a.TIMESTAMP, 'YYYYMMDD') = :PROCDATE " +
                    "     )," +
                    "     (select count(b) from PIXEL_LOG_CURR2 b" +
                    "       where to_char(b.TIMESTAMP, 'YYYYMMDD') = :PROCDATE " +
                    "     )" +
                    ") from Dual1" +
                    ""
    )
})

public class SourceCount {
    @Id
    private Long   COUNT;

    public SourceCount(Long COUNT1, Long COUNT2) {
        this.COUNT = COUNT1+COUNT2;
    }

    public Long getCOUNT() {
        return COUNT;
    }

    public void setCOUNT(Long COUNT) {
        this.COUNT = COUNT;
    }
}

Часть волшебства здесь заключается в том, чтобы создать фиктивную таблицу и вставить в нее одну запись.В моем случае я назвал ее Dual1, потому что моя база данных — Oracle, но я не думаю, что имеет значение, как вы называете фиктивную таблицу.

@Entity
@Table(name="DUAL1")
public class Dual1 {
    @Id
    Long ID;
}

Не забудьте вставить фиктивную запись:

SQL> insert into dual1 values (1);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top