Как присоединиться к двум несвязанным объектам, использующим JPA и Hibernate

У меня две таблицы: одна содержит адрес, а другая - фотографии. Единственным общим полем между ними является PersonID. Они были сопоставлены с двумя адресами POJO Classes и фотографией. Я смог получить данные в этих таблицах, создав критерии и добавив ограничения на поля. Как мы должны писать объединение в двух таблицах. Можно ли получить результат как два объекта -Address и Фото.

Я хочу сделать левое соединение, чтобы я мог записывать людей без фотографий. Я читал, что это возможно только с использованием hql, но возможно ли это, используя критерии?

Ответ 1

Вы можете легко написать запрос HQL, который будет возвращать результат в виде двух объектов, использующих Theta Join (как заметил Адриан). Вот пример:

String queryText = "select address, photo from Address address, Photo photo where address.personID=photo.personId";
List<Object[]> rows = session.createQuery(queryText).list();

for (Object[] row: rows) {
    System.out.println(" ------- ");
    System.out.println("Address object: " + row[0]);
    System.out.println("Photo object: " + row[1]);
}

Как вы видите, запрос возвращает список массивов Object [], который представляет каждую выбранную строку. Первый элемент этого массива будет содержать один элемент obejct, а второй - другой.

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

В случае левого соединения, я думаю, вам нужно использовать собственный SQL-запрос (а не запрос HQL). Вот как вы можете это сделать:

String queryText = "select address.*, photo.* from ADDRESS address 
                    left join PHOTO photo on (address.person_id=photo.person_id)";

List<Object[]> rows = sess.createSQLQuery(queryText)
                          .addEntity("address", Address.class)
                          .addEntity("photo", Photo.class)
                          .list();

Это должно работать для вашего дела.

Ответ 2

Как я объяснил в этой статье, у вас есть два варианта:

  1. С Hibernate 5.1 вы можете использовать ad-hoc для не связанных между собой объектов.

    Tuple postViewCount = entityManager.createQuery(
        "select p as post, count(pv) as page_views " +
        "from Post p " +
        "left join PageView pv on p.slug = pv.slug " +
        "where p.title = :title " +
        "group by p", Tuple.class)
    .setParameter("title", "High-Performance Java Persistence")
    .getSingleResult();
    
  2. До Hibernate 5.1 вы могли использовать только тета-стиль. Тем не менее, объединение в тета-эквивалент эквивалентно equijoin, поэтому вы можете только эмулировать INNER JOINs, а не OUTER JOINs.

    List<Tuple> postViewCount = entityManager.createQuery(
        "select p as post, count(pv) as page_views " +
        "from Post p, PageView pv " +
        "where p.title = :title and " +
        "      ( p.slug = pv.slug ) " +
        "group by p", Tuple.class)
    .setParameter("title", "Presentations")
    .getResultList();
    

Для получения дополнительной информации ознакомьтесь с этой статьей.

Ответ 3

Наконец, через 12 лет команда Hibernate реализовала такую функцию

Из документов Hibernate:

Предложение FROM также может содержать явные отношения, связанные с использованием ключевого слова join. Эти объединения могут быть как внутренними, так и левыми внешними стилями.

List<Person> persons = entityManager.createQuery(
    "select distinct pr " +
    "from Person pr " +
    "join pr.phones ph " +
    "where ph.type = :phoneType", Person.class )
.setParameter( "phoneType", PhoneType.MOBILE )
.getResultList();


List<Person> persons = entityManager.createQuery(
    "select distinct pr " +
    "from Person pr " +
    "left join pr.phones ph " +
    "where ph is null " +
    "   or ph.type = :phoneType", Person.class )
.setParameter( "phoneType", PhoneType.LAND_LINE )
.getResultList();

Или вы можете использовать ключевые слова WITH и ON. Замечание по этим

Важным отличием является то, что в сгенерированном SQL условия предложения WITH/ON являются частью предложения ON в сгенерированном SQL, в отличие от других запросов в этом разделе, где условия HQL/JPQL являются частью ГДЕ в сгенерированном SQL.

пример

List<Object[]> personsAndPhones = session.createQuery(
    "select pr.name, ph.number " +
    "from Person pr " +
    "left join pr.phones ph with ph.type = :phoneType " )
.setParameter( "phoneType", PhoneType.LAND_LINE )
.list();

В настоящее время я хочу попробовать новую функцию.

Ответ 4

Объединение двух несвязанных объектов возможно в Hibernate 5.1.

Например:

select objA from ObjectA objA   
JOIN ObjectB objB on objB.variable = objA.variable    
where objA.id = 1

Ответ 5

Что вы ищете

  1. HQL
  2. Присоединяйтесь к полям, которые вы не моделировали как отношения
  3. Left Join

(В то время, когда вопрос был задан первым, и этот ответ был дан) Hibernate поддерживает Theta Join, который позволяет вам делать 1 и 2. Однако для стиля тета-соединения доступно только внутреннее соединение.

Лично я бы рекомендовал вам моделировать правильные отношения, поэтому вам нужно всего лишь 1 и 3, которые хорошо поддерживаются в HQL.

(Еще один ответ на самом деле предоставил обновленную информацию о новой функции Hibernate, которая предоставляет такую функцию, о которой вы можете просто обратиться)

Ответ 6

Лучше всего иметь класс, содержащий те классы, к которым вы хотите присоединиться, чтобы объединить их все.

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