Как очистить и заменить коллекцию в отношениях один-ко-многим в Grails / Groovy - PullRequest
11 голосов
/ 15 января 2010

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

У меня есть отношение один ко многим между двумя объектами домена в моей модели в 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. Как очистить список во многих концах коллекции «один ко многим»?
  2. Как связать независимые объекты с родительским объектом и сохранить их индивидуально?

Спасибо

Ответы [ 4 ]

9 голосов
/ 27 октября 2013

Очистка 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/

8 голосов
/ 15 января 2010

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

activePerson.locations.clear()

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

activePerson.addToLocations(location)

, и когда вы сохраняете человека, отношение <-> человека к местоположению будет обновлено.

7 голосов
/ 28 мая 2014

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

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

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

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

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

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

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

0 голосов
/ 24 апреля 2019

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

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

...

activePerson.save()

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

...