Поведение при каскадном удалении "многие-к-одному" в Grails (GORM)

Я изо всех сил пытался создать правильные конфигурации для обеспечения поведения каскадного удаления в относительно простом проекте Grails.

Скажем, у меня есть следующие простые доменные классы:

class Author {
    String name
    static constraints = {
    }
}

и

class Book {
    String title
    Author author
    static constraints = {
    }
}

Если я создаю автора, а затем создаю книгу, написанную этим автором, я не смогу удалить автора, не удалив сначала книгу вручную. Я получаю сообщение «Нарушение ограничения целостности». Это не удивительно, поскольку MySQL (моя базовая база данных) создается Grails с «ограничением внешнего ключа» для столбца «автор» таблицы «книга» как «Ограничить» (и это поведение согласуется с ожиданиями Grails документация как я понимаю).

Теперь, если бы мне пришлось вручную изменить базовое ограничение базы данных для столбца «автор» таблицы книги с «Ограничить» на «Каскад», я получил бы желаемое поведение. А именно, что если вы удалите автора, все его книги также будут удалены.

Итак, что я хотел бы сделать, так это изменить мой класс Grails «Book» таким образом, чтобы в столбце автора была создана таблица «book» с «каскадом удаления». Я читал много информации о таких вещах и о значениях по умолчанию GORM с использованием «ownTo» и явных «сопоставлений».

Один из способов сделать это, основанный на документации для "ownTo", казалось, состоял в том, чтобы изменить строку в классе Book с:

Author author

to

static belongsTo = [author:  Author]

Таким образом, ясно указывается, что Автор является «стороной-владельцем» отношений. Документация, кажется, предполагает, что это должно вызвать поведение каскадного удаления, которое мне нужно. Однако это не сработает, если я не добавлю явное «hasMany = [books: Book]» в класс Author. Я не хочу этого делать. (Это желание имеет больше смысла в моей реальной сфере бизнеса, но даже как упражнение в понимании, я еще не понимаю, почему я должен явно знать о книгах в предметном классе Author).

Мне просто нужна настройка grails для изменения класса Book для создания настройки «каскадного удаления» в базе данных без изменения класса Author. Я пробовал использовать явное сопоставление, например:

static mapping = {
        author cascade: 'all'
}

и комбинации этого с другим явным отображением или опциями «принадлежит к». Это не сработало.

Заметив, что простое изменение «ограничений» в базовой базе данных SQL обеспечивает желаемое поведение, есть ли способ добиться этого с помощью Grails? Если нет, то я неправильно понял здесь что-то фундаментальное или я пытаюсь сделать что-то глупое?


person Glennn    schedule 01.05.2012    source источник
comment
Какую версию Grails вы используете?   -  person Sagar V    schedule 02.05.2012


Ответы (1)


Я думаю, вам не хватает обязательного поля типа Книга в Автор.

Вот пример кода, который соответствует документации (протестирован и работает)

class Author {

    String name
    Book book //you are probably missing this field

    static constraints = {
    }
}

class Book {

    String name

    static belongsTo = [author: Author]

    static constraints = {
    }
}

Тестовый пример:

@TestFor(Author)
@Mock([Book])
class AuthorTests {

    @Test
    void testAuthorBookCascades() {

        Author a = new Author(name: "Douglas Adams")
        Book b = new Book(name: "So Long, and Thanks for all the Fish")
        a.book = b
        a.save()

        assert Author.count() == 1
        assert Book.count() == 1

        a.delete()

        assert Author.count() == 0
        assert Book.count() == 0
    }
}

Как видите, вам нужен аргумент Book в Author. Нет необходимости в предложениях hasMany или hasOne.

person Sagar V    schedule 02.05.2012
comment
Спасибо, Сегар, но я надеялся найти способ, который не связан с изменением класса / таблицы Author, а просто каким-то образом изменяет каскадное поведение таблицы с книгами. Однако вы правы в том, что это работает (спасибо за усилие в изложении этого). Я начинаю думать, что, возможно, то, что вы сказали, является правильным способом сделать это, а то, о чем я прошу, просто не разработано в готовой GORM. - person Glennn; 02.05.2012
comment
@Glennn да, то, что вы спрашиваете, не определено, потому что этого не должно быть. Это будет означать, что спящий режим создаст ограничения, которые вы не указали, и не все хотят каскадного удаления всего. - person GalmWing; 02.05.2012
comment
@Glennn - Если есть внешние ограничения, лучше всего написать свои собственные функции для удаления, которые будут выполнять желаемое вами каскадное поведение. Что касается GORM, то, что говорит GalmWing, верно. - person Sagar V; 02.05.2012
comment
Спасибо, парни. Я написал свои собственные функции удаления. Просто подумал, что, возможно, есть более приятный способ настроить GORM для этого, которого мне не хватало. @GalmWing - Согласен. Я не хотел, чтобы GORM делал это по умолчанию - просто подумал, есть ли у меня способ настроить такое поведение. Доволен изложенными вариантами. - person Glennn; 10.05.2012