Как очистить и заменить коллекцию в отношениях "один ко многим" в 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()
Это очищает набор местоположений, а затем добавляет только те, которые в настоящее время выбраны в параметрах.