У меня есть интересное упражнение, пытающееся выбрать несколько производных сущностей, используя один запрос JPQL, в то время как с eclipselink 2.7.6.
Полиморфизм реализуется с использованием объединенного наследования. Диаграмма сущностей и классы java выглядят следующим образом:
+--------------+
| MainEntity |
+--------------+ +--------------+
| | --- myRef:OneToOne --- | Referenced |
+--------------+ +--------------+
| r: string |
+--------------+
^
|
+-----------+-----------+
| |
+--------------+ +--------------+
| Derived1 | | Derived2 |
+--------------+ +--------------+
| d1: string | | d2: string |
+--------------+ +--------------+
@Entity
@Table(name="MAIN_ENTITY")
public class MainEntity
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "MAIN_ENTITY_ID")
public Integer mainEntityId;
@OneToOne(optional = true)
@JoinColumn(name = "MY_REF", referencedColumnName = "REFERENCED_ID")
public Referenced myRef;
}
@Entity
@Table(name="REFERENCED")
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="REFERENCED_TYPE",discriminatorType=DiscriminatorType.STRING)
public abstract class Referenced
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "REFERENCED_ID")
public Integer referencedId;
@Column(columnDefinition = "TEXT", name = "R")
public String r;
}
@Entity
@Table(name="Derived1")
@DiscriminatorValue("DERIVED_1")
public class Derived1 extends Referenced
{
@Column(columnDefinition = "TEXT", name = "D1")
public String d1;
}
@Entity
@Table(name="Derived2")
@DiscriminatorValue("DERIVED_2")
public class Derived2 extends Referenced
{
@Column(columnDefinition = "TEXT", name = "D2")
public String d2;
}
Моя цель - создать один запрос, в результате чего таблица будет иметь общие столбцы (столбцы ссылочной сущности). присутствует слева, а также отдельные столбцы производных сущностей, представленные справа в одной таблице.
Если я инициализировал данные следующим образом:
Derived1 d1 = new Derived1();
d1.r = "R set from Derived1";
d1.d1 = "D1 set from Derived1";
MainEntity me1 = new MainEntity();
me1.myRef = d1;
Derived2 d2 = new Derived2();
d2.r = "R set from Derived2";
d2.d2 = "D1 set from Derived2";
MainEntity me2 = new MainEntity();
me2.myRef = d2;
em.getTransaction().begin();
em.persist(d1);
em.persist(me1);
em.persist(d2);
em.persist(me2);
em.getTransaction().commit();
Используя SQL я могу получить нужную таблицу, используя LEFT JOIN
операторы:
SELECT
m.MAIN_ENTITY_ID,
r.REFERENCED_ID,
r.R,
d1.D1,
d2.D2
FROM
REFERENCED r
INNER JOIN
MAIN_ENTITY m on m.MY_REF = r.REFERENCED_ID
LEFT JOIN
DERIVED1 d1 ON r.REFERENCED_ID = d1.REFERENCED_ID
LEFT JOIN
DERIVED2 d2 ON r.REFERENCED_ID = d2.REFERENCED_ID
Результаты:
MAIN_ENTITY_ID REFERENCED_ID R D1 D2
-------------- ------------- ------------------- -------------------- --------------------
2 1 R set from Derived1 D1 set from Derived1 [null]
1 2 R set from Derived2 [null] D1 set from Derived2
Однако пока мне сложно работать с JPQL тоже самое. Я пытался использовать любую комбинацию операторов JPE TREAT и (LEFT) JOIN, мне вообще не повезло. Либо результирующее объединение SQL приводит к тому, что идентификаторы d1 и d2 становятся равными (естественно, безрезультатных результатов), либо я получаю слишком много результатов, все они являются перестановками целевого результата, к которому я стремлюсь.
Я мог бы воспроизвести результат SQL, используя JPQL, используя комбинацию операторов TREAT и UNION, например:
SELECT
m.mainEntityId,
m.myRef.referencedId,
m.myRef.r,
TREAT(m.myRef AS Derived1).d1,
null as d2
FROM
MainEntity m
UNION
SELECT
m.mainEntityId,
m.myRef.referencedId,
m.myRef.r,
null as d1,
TREAT(m.myRef AS Derived2).d2
FROM
MainEntity m
Результаты:
mainEntityId referencedId r d1 d2
------------ ------------ ------------------- -------------------- ------------------
2 1 R set from Derived1 D1 set from Derived1 null
1 2 R set from Derived2 null D1 set from Derived2
Однако повторяя запрос Несколько раз с соответствующими null
выборками кажется неэффективным и подверженным ошибкам, потому что я вынужден повторять всю структуру для каждого подтипа. Особенно для более нормализованных моделей данных этот подход кажется чрезмерно не интуитивным.
Очевидно, я пытаюсь навязать парадигму SQL для JPQL, и, несмотря на небольшой успех, общее сообщение таково, что Я делаю что-то не так. Поэтому мой вопрос: есть ли лучший способ добиться этого с помощью JPQL? Если нет, что вы, люди, делаете в таком случае?
Заранее спасибо!