Vylepšení JPQL v JPA 2.1 a Java EE 7 (část 1 – JOIN ON)
Java EE 7 existuje již několik let a poskytuje několik velmi užitečných a dlouho očekávaných funkcí, jako jsou grafy entit a lepší podporu pro uložené procedury a mapování výsledků. Pro přehled se podívejte na blogový příspěvek Thorbena Janssena. Rád bych však přidal podrobnější shrnutí funkcí v dotazovacím jazyce JPA. Všechny jsou dostupné v JPQL i Criteria API:
- ZAPNUTO klíčové slovo pro specifikaci podmínek pro JOIN
- FUNKCE zavolat libovolnou databázovou funkci
- LÉČBA převést entity na jejich konkrétní typ
V tomto příspěvku se zaměřím na první přídavek. Další 2 přidám do dalších příspěvků.
ZAPOJTE SE
Výrazy JOIN v JPA jsou již trochu odlišné od JOIN ve standardním SQL. JOIN je možné použít pouze tehdy, když již existuje mapování mezi entitami, a není vždy nutné kvůli línému načítání souvisejících kolekcí pomocí implicitních spojení. Buďte opatrní s JPA JOIN, pokud jste začátečník s JPA, a pečlivě si přečtěte dokumentaci.
Do JPA 2.1 bylo možné filtrovat konečné výsledky dotazu pouze pomocí podmínek v klauzuli WHERE. To je ve většině případů dostačující. Ale při použití LEFT JOIN narážíte na limit a chcete omezit to, co se má připojit od druhé entity. S LEFT JOIN vždy získáte alespoň jeden řádek z první entity, ale někdy nechcete připojit žádné instance z druhé entity, takže konečná kolekce zůstane prázdná.
Kromě klíčového slova WITH v Hibernate neexistoval v JPA žádný standardní způsob, jak to udělat. Od JPA 2.1 je možné přidat podmínku ke spojením s ZAPNUTO klíčové slovo, podobné SQL JOIN ON.
Příklad použití JOIN ON v JPA
SELECT a FROM Person p LEFT JOIN p.addresses a ON a.city = p.city
Výše uvedený úryvek načte pouze ty adresy, které mají stejné město jako osoba. Totéž lze dosáhnout přesunem podmínky do WHERE, takže potřebujeme složitější příklad s více spojeními, abychom viděli výhodu:
Příklad použití JOIN ON v JPA
SELECT c FROM Person p LEFT JOIN p.addresses a ON a.city = p.city LEFT JOIN a.country c ON c.region = 'Europe'
Ve výše uvedeném příkladu dostaneme pouze země, kde a adresa existuje a jejich osoba má stejné město. Jaký je rozdíl oproti použití WHERE? Pokud bychom obě podmínky z klauzulí ON dali do WHERE na konci, zahrnuli bychom všechny země vztahující se ke všem adresám osoby, nikoli pouze k adresám se stejným městem. Je jasné, že výsledek by mohl být větší, když podmínku aplikujeme až na konci. ZAPNUTO klíčové slovo umožňuje filtrovat výsledky po každém spojení, což vede k menšímu výsledku po každém následném spojení.
Jedno omezení však stále přetrvává i při použití JOIN s ON – entity lze stále spojovat pouze tehdy, jsou-li spolu mapovány jako související entity.
JOIN ON s více kořeny v Eclipselink
Eclipselink poskytuje další funkci ke standardnímu klíčovému slovu JPA On. Umožňuje spojit nesouvisející entity ve stavu ON, což umožňuje PŘIPOJIT nesouvisející entitu k jiným entitám, které jsou již v dotazu. Proto nevyžaduje, aby byla pole označena jako související, i když potřebujeme podmínku spojení pouze pro jednu sestavu a nechceme aktualizovat naše mapování. Také testy, které generují databázové tabulky a omezení z mapování, to z nějakého důvodu nebudou chtít (např. pokud by došlo k porušení omezení v obrovském množství testovacích dat).
Zde je příklad rozšířeného použití ON v Eclipselink (není součástí standardu JPA 2.1). Tento spojuje osoby se stejným názvem města:
JOIN ON s více kořenovými entitami
SELECT p FROM Person p LEFT JOIN Person p2 ON p2.city = p.city