Получение и обновление GORM партиями - PullRequest
0 голосов
/ 17 июня 2020

Мне нужно обновить одно свойство для большого набора данных в базе данных Oracle с помощью grails 2.5

Сейчас мой код выглядит примерно так:

    List booksToUpdate = []
    boolean moreBooks = true
    int offset = 0

    while (moreBooks) {
        def fetchedBooks = []
        if('Europe'){
            fetchedBooks = Book.findAllByAuthorInList(getEuropeanAuthors(),
                    [max: BATCHSIZE, offset: offset])
        } else {
            fetchedBooks = Book.findAllByAuthorInListAndPublishYear(getEnglishAuthors(), '1999',
                    [max: BATCHSIZE, offset: offset])
        }

        booksToUpdate.addAll(fetchedBooks)

        moreBooks = fetchedBooks.size() == BATCHSIZE
        offset += BATCHSIZE
    }

    booksToUpdate.each { book ->
        book.copyright = '2020'
        book.save(flush: true, failOnError: true)
    }

Я бы хотел бы пакетировать мои обновления для производительности. Кроме того, запрос findAll отличается очень незначительно, и было бы неплохо построить критерии поиска условно. В идеале мне нужно что-то вроде этого:

    while (moreBooks) {
        def fetchedBooks = []

        def criteria = new DetachedCriteria(Book)
        criteria.build [max: BATCHSIZE, offset: offset] {
            List relevantAuthors = []
            if('Europe') {
                relevantAuthors = getEuropeanAuthors()
                eq 'publishYear', '1999'
            } else {
                relevantAuthors = getEnglishAuthors()
            }
            inList 'author', relevantAuthors
        }
        criteria.updateAll(copyright:'2020') //batch update

        moreBooks = fetchedBooks.size() == BATCHSIZE
        offset += BATCHSIZE
    }

Есть способ сделать это? Не обязательно с DetachedCriteria. Я посмотрел на руководство , но ничего не могу найти о передаче max и offset. Есть ли лучший способ сделать код более элегантным без ущерба для его производительности?

1 Ответ

0 голосов
/ 24 июня 2020

updateAll обновляет все, даже если по умолчанию установлены max и offset. И я понял, что мне нужно вернуть список обновленных экземпляров. Поэтому пытаться объединить все в один updateAll, который возвращает только count, не имело смысла. В итоге получилось:

List updateCopyright(String geo) {
    DetachedCriteria<Book> findCr = getQueryFromGeo(geo)
    
    List<String> updatedBookIds = []
    boolean moreBooks = true
    int offset = 0
    
    while (moreBooks) {
        List<Book> fetchedBooks = findCr.list([max: BATCHSIZE, offset: offset])
        List currentBatchIds = fetchedBooks*.id

        def updateCr = Book.where {
            inList 'id', currentBatchIds
        }
        int updatedCount = updateCr.updateAll(copyright: '2020')

        moreBooks = updatedCount == BATCHSIZE
        offset += BATCHSIZE

        updatedBookIds.addAll(currentBatchIds)
    }

    updatedBookIds
}


private DetachedCriteria<Book> getQueryFromGeo(String geo) {
    switch (geo) {
        case 'Europe':
            return Book.where {
                author in getEuropeanAuthors()
            }
        case 'England':
            return Book.where {
                author in getEnglishAuthors() &&
                        publishYear == '1999'
            }
        default:
            return Book.where {}
    }
}

Также играл с построением моего запроса условно с помощью createCriteria, но пострадала читаемость и не было проверки во время компиляции, которая идет с where запросами

...