Как очистить и заменить коллекцию в отношениях "один ко многим" в Grails/Groovy

Этот вопрос состоит из двух частей: первая часть - это очистка списка, а вторая часть - назначение владельца объекту.

У меня есть отношение "один ко многим" между двумя объектами домена в моей модели в Grails. Отношение выглядит следующим образом:

class Person {

    static hasMany = [authorities: Role, locations: Location]
}

class Location {

    static belongsTo = Person

}

В моем приложении список locations на Person полностью обновлен и заменен новым списком в действии пользователя. Чем больше я получаю список объектов Location, не зависимых от связанного Person. Я разрешаю, к кому применить их, путем извлечения текущего зарегистрированного пользователя, который я называю activePerson и подходит для моих целей.

Что я хочу сделать, это удалить все существующие местоположения на activePerson и вставить все новые, связав их с activePerson по мере того, как я иду. У меня есть куча свойств на Person, которые я не хочу останавливать на этом этапе, поэтому я хочу избежать сохранения всего родительского объекта только потому, что изменили местоположение детей.

Я подумал об итерации в списке activePerson.locations и удалив их один за другим и полагаясь на GORM/Hibernate, чтобы объединить запросы вместе и выполнить флеш в конце. Это кажется грубой силой, хотя это может сработать. Я ожидал, что будет метод clearLocations или что-то подобное, но я не могу его найти.

Если я просто заменил activePerson.locations новым списком и вызовом activePerson.save(flush:true), будет ли GORM обрабатывать удаление существующих строк?

Во-вторых, я хочу поместить новые объекты Location на activePerson. Снова я мог бы заполнить activePerson.locations и сохранить все это, но я хотел бы избежать этого, если смогу. Я могу сохранить их индивидуально, но как я могу установить belongsTo для каждого объекта Location, когда я иду?

Итак, чтобы повторить:

  • Как очистить список на многих концах коллекции "один ко многим"?
  • Как связать независимые объекты с родительским объектом и сохранить их отдельно?

Спасибо

Ответ 1

Очистка Collection не помогла мне:

activePerson.locations.clear()

Просто попробуйте выполнить итерацию по коллекции, избегая ConcurrentModificationException, вызывая collect():

activePerson.locations.collect().each {
    item.removeFromLocations(it)
}

И после этого сохраните сущность для выполнения инструкции SQL:

activePerson.save flush:true

Ссылка на статью, чтобы узнать больше: http://spring.io/blog/2010/07/02/gorm-gotchas-part-2/

Ответ 2

Для # 1 вы можете очистить коллекцию (она по умолчанию установлена):

activePerson.locations.clear()

Для # 2 используйте addToLocations:

activePerson.addToLocations(location)

и когда вы сохраните человека, будет изменено местоположение ↔ person.

Ответ 3

Хотя это старый вопрос, я столкнулся с очень похожей ситуацией, в которой я хотел обновить набор дочерних записей. Вот как я решил его решить. Для простоты я буду использовать те же имена объектов/отношений, что и вопрос о вопросе.

  • В блоке mapping родительского домена добавьте:

    static mapping = {
        locations(cascade: "all-delete-orphan")
    }
    
  • В дочернем домене добавьте аннотацию @EqualsAndHashCode (на всякий случай, когда кто-то скрывается, я имею в виду groovy.transform.EqualsAndHashCode).

  • Добавьте все дочерние элементы в родительский домен, используя методы Grails addTo (например, addToLocations), а затем сохраните родительский домен.

В то время как этот подход требует сохранения родительского домена (чего не хотел делать айзер), кажется, что это наиболее подходящий подход, учитывая четкое определение belongsTo в модели. Поэтому я бы ответил на вопрос таких нужных вопросов:

  • Вместо того, чтобы делать это вручную, пусть Grails/Hibernate очищает записи, задавая поведение каскада all-delete-oprhan в отношении.

  • Не пытайтесь сохранить дочерние записи напрямую, но вместо этого сохраните родительский объект в соответствии с тем, что, по-видимому, ожидает Grails.

Ответ 4

Вот что у меня работает:

activePerson.locations.clear() activePerson.properties = params

...

activePerson.save()

Это очищает набор местоположений, а затем добавляет только те, которые в настоящее время выбраны в параметрах.