Grails — предотвращение рекурсивного отношения «один ко многим»

#grails #grails-orm

#grails #grails-orm

Вопрос:

У меня есть следующий класс домена в Grails:

 class TreeNode {
    String name
    String description

    static hasMany = [childNodes: TreeNode]
}
  

Какой наиболее идиоматичный способ Grails гарантировать, что экземпляр TreeNode не может иметь себя в качестве дочернего элемента? Могу ли я сделать это как ограничение в классе домена или я должен писать пользовательский код в действии сохранения в TreeNodeController?

Ответ №1:

Сделайте это как пользовательское ограничение.

 static constraints = {
  childNodes(validator: {value, obj, errors->
      if(value.contains(obj) {
        errors.rejectValue('childNodes', 'Cannot contain self')
      }
  }
}
  

Ответ №2:

Ответ зависит от того, насколько глубоко вы хотите проверить дочерние элементы. Если вы беспокоитесь только о непосредственных дочерних элементах, то код из @Tiggerizzy должен работать просто отлично.

Если, с другой стороны, вы хотите убедиться, что узел не является непосредственным или глубоким дочерним элементом в вашем дереве, тогда логику следует вывести из проверки и поместить в класс обслуживания Grails. Это дало бы как минимум два преимущества:

  1. Если другие свойства в узле изменяются, но не структура дерева, вы можете пропустить проверку дочерних элементов и сэкономить дополнительное время обработки при проверке.
  2. Если вы выполняете проверку вблизи или в корне дерева, то проверка всех дочерних элементов будет более длительным процессом для большого дерева, требующим много работы с базой данных. Выполняя эту работу в классе сервиса, вы получаете транзакционный характер сервиса, который будет откатывать любые изменения базы данных при необработанном Exception , например, в ситуации оптимистичной блокировки с другим потоком.