Използване на JOIN
не работи за това.
Вашата заявка ще бъде доста неефективна, защото ако използвате присъединяване по този начин, вие създавате декартов продукт между книгите и таблицата със статии, което води до доста потребление на памет и процесор както в базата данни, така и във вашия Java клиент, преди да премахнете дублирането на всички безсмислени комбинации.
"Правилният" SQL подход би бил да се използва MULTISET
както е описано в тази статия тук
. За съжаление, jOOQ 3.9 не поддържа MULTISET
все още
(нито много бази данни). Така че трябва да създадете две отделни заявки:
- Извличане на всички книги
- Извличане на всички статии
И след това използвайте нещо като Java 8 Streams, за да ги съпоставите в един обект.
Използване на MULTISET
започвайки от jOOQ 3.15
За щастие, започвайки от jOOQ 3.15, има готово решение за вмъкване на колекции в SQL с помощта на MULTISET
. Вашата заявка ще изглежда така:
Използване на отражение
List<Author> authors =
ctx.select(
AUTHOR.ID,
AUTHOR.NAME,
multiset(
select(BOOKS.TITLE)
.from(BOOKS)
.where(BOOKS.AUTHOR_ID.eq(AUTHOR.ID))
).as("books"),
multiset(
select(ARTICLES.TITLE)
.from(ARTICLES)
.where(ARTICLES.AUTHOR_ID.eq(AUTHOR.ID))
).as("articles")
)
.from(AUTHOR)
.where(AUTHOR.ID.eq(id))
.fetchInto(Author.class);
Използване на безопасно тип, реклама -hoc преобразуване
List<Author> authors =
ctx.select(
AUTHOR.ID,
AUTHOR.NAME,
multiset(
select(BOOKS.TITLE)
.from(BOOKS)
.where(BOOKS.AUTHOR_ID.eq(AUTHOR.ID))
).as("books").convertFrom(r -> r.map(Record1::value1)),
multiset(
select(ARTICLES.TITLE)
.from(ARTICLES)
.where(ARTICLES.AUTHOR_ID.eq(AUTHOR.ID))
).as("articles").convertFrom(r -> r.map(Record1::value1))
)
.from(AUTHOR)
.where(AUTHOR.ID.eq(id))
.fetch(Records.mapping(Author::new));
За повече информация относно MULTISET
, моля, вижте тази публикация в блог
, или ръчните секции:
Използване на SQL/XML или SQL/JSON, започвайки от jOOQ 3.14
Започвайки от jOOQ 3.14, можете да вложите колекции чрез SQL/XML или SQL/JSON, ако вашата RDBMS поддържа това. Можете да създадете документ и след това да използвате нещо като Gson, Jackson или JAXB, за да го съпоставите обратно с вашите Java класове. Например:
List<Author> authors =
ctx.select(
AUTHOR.ID,
AUTHOR.NAME,
field(
select(jsonArrayAgg(BOOKS.TITLE))
.from(BOOKS)
.where(BOOKS.AUTHOR_ID.eq(AUTHOR.ID))
).as("books"),
field(
select(jsonArrayAgg(ARTICLES.TITLE))
.from(ARTICLES)
.where(ARTICLES.AUTHOR_ID.eq(AUTHOR.ID))
).as("articles")
)
.from(AUTHOR)
.where(AUTHOR.ID.eq(id))
.fetchInto(Author.class);
Имайте предвид, че JSON_ARRAYAGG()
агрегира празни набори в NULL
, а не в празен []
. Ако това е проблем, използвайте COALESCE()