sim
sim

Reputation: 3602

Grails - Preventing a recursive one-to-many relationship

I have the following domain class in Grails:

class TreeNode {
    String name
    String description

    static hasMany = [childNodes: TreeNode]
}

What is the most idiomatic Grails way of ensuring that an instance of TreeNode cannot have itself as a child? Can I do this as a constraint in the domain class, or should I be writing custom code in the Save action on the TreeNodeController?

Upvotes: 1

Views: 756

Answers (2)

schmolly159
schmolly159

Reputation: 3881

The answer depends on how deep you want to check within the children. If you are only worried about the immediate children, then the code from @Tiggerizzy should work just fine.

If on the other hand you want to verify that the node isn't an immediate or deep child in your tree, then the logic should be pulled out of validation and placed within a Grails Service class. This would offer at least two benefits:

  1. If other properties in the node change, but not the structure of the tree, you can skip the children check validation and save yourself the extra processing time when validating.
  2. If you are validating from near or at the root of the tree, then verifying all of the sub-children would be a longer process for a large tree, involving a lot of database work. By doing this work in a Service class you gain the Service's transactional nature, which will roll back any database changes on an unhandled Exception such as in an optimistic lock situation with another thread.

Upvotes: 1

Ben Doerr
Ben Doerr

Reputation: 1655

Do it as a custom constraint.

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

Upvotes: 1

Related Questions