Когда следует использовать hasMany для отношений N: 1 в классах домена grails? - PullRequest
5 голосов
/ 29 июня 2010

В Grails я могу реализовать отношение N: 1, например:

class Parent { hasMany = [children:Child] }
class Child  { belongsTo = [parent:Parent] }

Теперь (если addTo и removeFrom всегда правильно используются), я могу получить детей Родителя через parent.children.

Но я также могу сделать это без hasMany:

class Parent { }
class Child  { belongsTo = [parent:Parent] }

Затем я должен использовать Child.findAllByParent (parent), чтобы получить всех детей.

Мой вопрос: есть ливажные причины, по которым мне следует использовать hasMany, если можно также запрашивать дочерние элементы родителя и по-другому?

Я полагаю, что иногда проще (и, возможно, быстрее, если его извлекают вместе с родителем?) просто обратиться кparent.children, но с другой стороны этот список может стать довольно длинным, когда есть несколько детей.И что мне не нравится в hasMany, так это то, что вам всегда нужно позаботиться о addTo или removeFrom или очистить сеанс после добавления нового Child с Parent, чтобы grails делал это автоматически ...

Является ли ответом то, что вы должны просто использовать hasMany, если детей мало, и не использовать его, если их много (по соображениям производительности), или за этим стоит больше?

Ответы [ 2 ]

8 голосов
/ 29 июня 2010

Использование hasMany по сравнению с ownTo больше относится к каскадному поведению, которое вы хотите указать, когда происходит обновление / удаление. Во втором примере для каскадирования установлено значение ALL на дочерней стороне и NONE на родительской стороне. Если вы удалите ребенка, с родителем ничего не произойдет. Если вы удалите родителя, все дети будут автоматически удалены.

В вашем первом примере для каскадирования установлено значение ALL на родительской стороне и SAVE-UPDATE на дочерней стороне. Так что теперь вы можете сделать что-то вроде:

parent.addToChildren(child1)
parent.addToChildren(child2)
parent.addToChildren(child3)
parent.save(flush:true)

И когда вы сохраните родительский элемент, все дочерние элементы будут обновлены.

Касаясь чего-то, чего вы не просили, вы также можете предположить что-то вроде:

class Parent { hasMany = [children:Child] }
class Child  { Parent parent }

Если вы определите отношения между дочерним элементом и родительским способом таким образом, вам потребуется вручную управлять дочерними объектами, которые ссылаются на родительского элемента при удалении родительского элемента *. (* это исправляет предыдущее утверждение, которое оказалось неточным)

Итак, hasMany / ownTo имеет два основных соображения:

  1. Какую каскадную стратегию вы хотите выполнить при обновлении / удалении
  2. Как вы, скорее всего, собираетесь обращаться к данным, если вы ожидаете, что вам нужно получить набор потомков для родителя, использование метода parent.getChildren () довольно удобно.

UPDATE:

Я также хочу уточнить, GORM не будет загружаться при использовании hasMany; по умолчанию GORM использует стратегию отложенного выбора, поэтому он не получит дочерние элементы до тех пор, пока не будет предпринята попытка доступа к parent.children

Если вы хотите, чтобы по умолчанию с нетерпением выбиралась связь, вы можете указать соответствующее отображение:

class Parent { 
  hasMany = [children:Child]
  static mapping = {
    children lazy:false
  }
}

Наконец, вы упомянули, что вам не нравится, что вам нужно беспокоиться о addTo / removeFrom на стороне hasMany. Вам не нужно делать это, если вы сохраняете с помощью flush: true.

def parent = Parent.get(id)
def child = new Child(name:'child1', parent:parent)
if(child.save(flush:true)) {
  // both sides of the relationship should be good now
} 

РЕДАКТИРОВАТЬ: исправлен обратный порядок значений по умолчанию для дочернего / родительского каскада и исправлено неправильное представление о том, как Горм обрабатывает отношения без принадлежности.

0 голосов
/ 06 января 2012

Отличный вопрос, и в настоящее время принят хороший ответ.Есть еще один важный аспект производительности, который происходит при добавлении и сохранении нового дочернего элемента.В первом примере Grails по умолчанию должен загрузить весь список дочерних элементов из базы данных, прежде чем вставить новый в Set, чтобы гарантировать уникальность.Во втором случае это не так, что приводит к гораздо лучшей производительности.Вы можете обойти это поведение в своем первом примере, определив детей как «Коллекцию» согласно http://grails.org/doc/latest/guide/single.html#sets,ListsAndMaps

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...