В базе данных, которая собирает авторов и их книги, мы добавляем книги как Author
как Book
экземпляров.
Однако Author
может содержать книги, которые еще не были добавлены в базу данных. Вот почему у нас есть внешний счетчик здравомыслия, сообщающий нам, сколько книг на самом деле опубликовано Author
. Если numberOfKnownBooks
равно количеству Book
экземпляров в базе данных, то мы считаем, что у нас есть полная библиография Author
.
![Data Model](https://i.stack.imgur.com/WtBE9.png)
Запрос SQL для получения всех Authors
, чья библиография завершена, будет записан в SQL следующим образом:
select author.id, count(*)
from book inner join author on book.author_id=author.id
group by author.number_Of_Known_Books, author.id
having count(*) = author.number_Of_Known_Books
Сложность заключается в том, что соединение указывает в противоположном направлении, и обычные примеры обычно показывают, как создать запрос для получения Books
, объединенного с Authors
, а не наоборот.
Я нашел несколько статей в stackoverflow, объясняющих, как сделать что-то подобное в простом JPQL (минус группу из-за ... с усложнением) здесь , но делать это в DSL, ожидаемом @Query
аннотация в Службе данных в GORM 6.1+, я получаю исключение, возникающее в подземельях сгенерированного кода AST, сообщающее, что он не может найти метод executeQuery
в java.lang.Object
. Это разумная жалоба, но я понятия не имею, почему это происходит. К сожалению, нет возможности пошаговой отладки этого кода.
Это моя служба данных:
import grails.gorm.services.Query
import grails.gorm.services.Service
@Service
abstract class AuthorService {
@Query("""
select a.*, count(a.id)
from ${Book b} join ${b.author} a
group by a.numberOfKnownBooks, a.id
having count(*) = a.numberOfKnownBooks
""")
abstract List<Author> retrieveCompleteAuthors()
}
ОБНОВЛЕНИЕ : удалены ненужные аннотации @GrailsCompileStatic и @Transactional согласно инструкциям Джеффа
ПОЛНОЕ РЕШЕНИЕ , с правильным запросом JPQL:
@Service(Author)
abstract class AuthorService {
@Query("""
select auth from ${Author auth} where auth.id in (
select a.id
from ${Book b} join ${b.author} a
group by a.numberOfKnownBooks, a.id
having count(*) = a.numberOfKnownBooks
)
""")
abstract List<Author> retrieveCompleteAuthors()
}