23

Here's what I'd like to do:

class A {
  String string
  static constraints = {
    string(maxSize:100)
  }
}

class B extends A {
  static constraints = {
    string(url:true)
  }
}

So class A should have some constraints and B should have the same plus additional constraints on the same property.

I couldn't get that to work though and I can imagine that it would clash with the Table-per-Hierarchy concept.

So I tried to work around that problem by introducing a Command object with class B's constraints which can be validated in the constructor of class B. However it seems that Command objects can only be used within controllers (grails keeps saying that there is no .validate() method for it).

So my question is: What is the most elegant way to solve this using grails constraints (not re-implementing the validation manually)? Could be...

  • Switching to Table-per-Sub-Class concept?
  • Making the Command Object work in the Domain class somehow?
  • Any other way?

Edit: It would be okay for me to define all the constraints in the child classes, repeating the constraints of the parent class or not even having constraints in the parent class at all. But the solution should work for multiple child classes (with different constraints) of the same parent class.

Jörg Brenninkmeyer
  • 3,304
  • 2
  • 35
  • 50
  • I'm not sure every constraint will work this way, as by default inherited classes are mapped to same DB table. So if you have class C with non-null, unique constraints on C.c, it will impose DB table constraint on whole table A - and c field will be there for all classes, and will be null for anything but C instances. – Victor Sergienko Oct 22 '10 at 14:29
  • Yeah, that's why I brought Table-per-Sub-Class into play. – Jörg Brenninkmeyer Oct 23 '10 at 13:45

4 Answers4

7

You can use

    class B extends A {
       static constraints = {
          importFrom A
          //B stuff
       }
    }

as states in http://grails.org/doc/latest/ref/Constraints/Usage.html

RoberMP
  • 1,306
  • 11
  • 22
5

The way it was in 2.x:

As constraints is a closure executed by some ConstraintsBuilder, I'd try calling it from B, like

class B extends A { 
  static constraints = { 
    url(unique: true)
    A.constraints.delegate = delegate  # thanks Artefacto
    A.constraints()
  } 
}
Victor Sergienko
  • 13,115
  • 3
  • 57
  • 91
  • 1
    Close. You have to change `A.constraints`'s delegate first though: `A.constraints.delegate = delegate`. But thanks for pointing me in the right direction. – Artefacto Mar 06 '13 at 09:04
  • 2
    @Artefacto - Would you be able to post an answer that works, or edit this answer to make it work? I know of others that have had this question. Thanks! – cdeszaq Apr 04 '14 at 23:53
  • i've tried it with grails 2.0.4 (with grails console) and it doesnt work, it throws an error in a phase where A.contraints doesnt have the delegate property – jneira Feb 24 '17 at 12:02
1

Basically I do not see how it can be done.

Design wise a domain class actually maps the structure of the database table. The constraints will actually generate DB constraints. So your are trying to make several objects that will generate different constraints on the same table.

I think the better approach would be to create one domain object that has the simplest subset of constraints and then use different command objects to fine tune the exact constraints you want to be passed to the domain.

You could also use the validator: in the constraints to fine tune different constraints for different objects types (something like a types column in the domain and based on different types do different validation).

Demian
  • 941
  • 6
  • 6
-1

You need to redeclare the superclass constraints because it's a static clojure (static properties and static methods doesn't are inherited by child classes), so, it's not mapped by GORM.

Cheers.

mannysz
  • 951
  • 8
  • 19