SqlResultSetMapping с таблицей самостоятельного соединения - PullRequest
0 голосов
/ 23 июля 2010

У меня есть запрос с самостоятельным соединением, который выглядит следующим образом:

выберите t1. , t2. из таблицы t1 левой таблицы внешнего соединения t2 на t2.LFT t1.RGT AND t2.REG_CODE_PAR = 'ALL' И t1.STATUS_CODE = 'A' И t2.STATUS_CODE = 'A'

Я использую @NamedNativeQuery с набором результатов, сопоставленным сполучить результат.

@NamedNativeQuery(
    name="findTree",
    query="..... the query above", 
    resultSetMapping = "regionT")

Со следующим отображением набора результатов

@SqlResultSetMapping(name = "regionT" , entities ={
    @EntityResult( 
        entityClass = Tree.class
        fields = {
            @FieldResult(name = "regCode", column = "REG_CODE")
            @FieldResult(name = "rgt", column = "RGT"),
            @FieldResult(name = "lft", column = "LFT"),
            @FieldResult(name = "name", column = "NAME"),
            @FieldResult(name = "regCodePar", column = "REG_CODE_PAR"),
            @FieldResult(name = "statusCode", column = "STATUS_CODE")
        }
    ),
    @EntityResult(
        entityClass = TreeSelf.class
        fields = {
            @FieldResult(name = "regCode1", column = "REG_CODE")
            @FieldResult(name = "rgt1", column = "RGT"),
            @FieldResult(name = "lft1", column = "LFT"),
            @FieldResult(name = "name1", column = "NAME"),
            @FieldResult(name = "regCodePar1", column = "REG_CODE_PAR"),
            @FieldResult(name = "statusCode1", column = "STATUS_CODE")
        }
    )
})

Содержимый класс сущности выглядит следующим образом.

@NamedNativeQuery(...)
@SqlResultSetMapping(...)
@Entity
@Table(name = "table")
public class Tree implements Serializable {

    @Id
    @Column(name = "REG_CODE")
    private String regCode;  ... ..getters and setters...}

Когда я запускаю запросиспользуя em.createQuery ("findTree"), я получаю один и тот же объект в обоих

1-м и 2-м элементах возвращаемого массива объектов.Даже если я создаю класс TreeSelf, идентичный Tree, и использую его как 2-й

EntityResult вместо двух EntityResults, использующих один и тот же entityClass, я получу тот же

результат.

Может кто-нибудь указать, что не так с конфигурацией?

1 Ответ

1 голос
/ 23 июля 2010

Посмотрим, пойму ли я ваш вопрос.Вы ожидаете получить две Tree сущности из каждой строки результатов собственного запроса.Первый объект должен быть сформирован из столбцов t1.Вторая сущность должна быть сформирована из столбцов t2.Вопреки ожиданиям вы фактически получаете два экземпляра, сформированные из t1.Экземпляры от t2 не отображаются.Во время отладки вы создали сущность двойника для Tree с именем TreeSelf, но TreeSelf в конечном счете не требуется, и вы хотите от нее избавиться.Остановите меня, если что-то из этого было не так.

Я думаю, что проблема связана с неоднозначными именами столбцов.Каждое имя столбца в собственном запросе появляется дважды, один раз из t1 и один раз из t2.Кажется, что средство отображения результатов произвольно выбирает первое вхождение каждого неоднозначного имени столбца для обоих Tree объектов.Я удивлен, что работает на всех.Я бы ожидал, что SQLException пожалуется на неоднозначность ссылок на столбцы.

Кроме того, вы уверены, что хотите использовать внешнее левое соединение?Что если не найдено совпадений для строки t1?Он будет связан со всеми NULL в столбцах t2.Тогда у вас есть нулевая Tree сущность.Я думаю.Я даже не знаю, что в этом случае сделает маппер результата.Возможно, вам нужно внутреннее объединение?

Рассмотрите возможность перевода этого собственного запроса в запрос JPQL.(JPA Criteria API также хорош, но я считаю его более громоздким для примеров.) Вот JPQL-версия собственного запроса:

SELECT t1, t2 
FROM Tree t1, Tree t2
WHERE t2.lft < t1.lft AND t2.rgt > t1.rgt AND t2.regCodePar = 'ALL' AND
      t1.statusCode = 'A' AND t2.statusCode = 'A'

NB : Это меняет семантику соединениявнутрь, а не слева.

Вот эскиз кода, который может выполнить этот запрос:

EntityManager em = ... // EntityManager by injection, EntityManagerFactory, etc.
String jpql      = ... // Like example above
TypedQuery<Object[]> q = em.createQuery(jpql, Object[].class);

for (Object[] oa : q.getResultList()) {
   Tree t1 = (Tree)oa[0];
   Tree t2 = (Tree)oa[1];
}

Если вы по какой-либо причине застряли с собственным запросом, вот как вы можете это сделатьобойти столбец имя двусмысленность.Вместо того, чтобы начинать собственный запрос, такой как select t1.*, t2.*, псевдоним каждого столбца с AS.Предложение SELECT будет выглядеть следующим образом:

SELECT t1.REG_CODE AS t1_REG_CODE, t1.RGT AS t1_RGT, (... rest of t1 cols ...), 
       t2.REG_CODE AS t2_REG_CODE, t2.RGT AS t2_RGT, (... rest of t2 cols ...)

Атрибут column в каждом FieldResult должен соответственно изменяться.Таким образом, атрибуты column под первым EntityResult должны начинаться с t1_, а вторые атрибуты должны начинаться с t2_.

. Я бы настоятельно рекомендовал удалить собственный запрос и сопоставитель результатов sql ииспользуя JPA Query Language или Criteria API, если вы можете найти способ.

Обновление : Как подтверждается в ваших комментариях, полезный ответ на ваш вопрос должен сохранять семантику левого (внешнего) соединения.К сожалению, JPQL и Criteria API не поддерживают сложные условия левого соединения.Невозможно квалифицировать левое соединение JPQL с явным условием ON.

Насколько мне известно, единственный способ выполнить левое внешнее соединение в соответствии со спецификацией - это пройти через отношения сущностей.Затем реализация JPA генерирует условие ON, которое проверяет равенство идентичности.Соответствующими спецификационными битами являются 4.4.5 «Объединения» и 4.4.5.2 «Левые внешние соединения».

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

...