I have a Grails application with a bunch of domain classes, some with many fields, some of which have a hasMany
relationship with the domain class in question. For this particular application I only have one "constraint", that is that every instance of every domain class must be unique. I don't care if an arbitrary field has the same value across multiple instances of the same domain class, so long as each instance is made unique by the value of some other field in that domain class. So basically I want validation to take place at a domain class instance level instead of the domain class field level. Right now I am doing that by using the very groovy @EqualsAndHashCode
annotation to generate my equals
and hashCode
methods, then calling equals
in a custom validator on some arbitrary field of a domain class.
Two questions:
- Is there a more efficient way of validating a domain class is unique?
- If no, then is there a way I can call my custom validator code on the domain class instance itself instead of going through one of the fields of the domain class instance?
@groovy.transform.EqualsAndHashCode class MyDomainClass { String some int arbitrary boolean field static constraints = { // The field I chose to validate on is irrelivant, I just need to run the validation code **somewhere** arbitrary validator: { val, obj -> return !MyDomainClass.getAll().contains(obj) } } }
I should also add I'm looking for a generic (hopefully efficient) way to do this. I realize calling getAll()
is very inefficient and instead calling some variant of find
or performing an HQL query on the exact fields of each domain class would be much more efficient... it just takes a lot longer to write!
Examples
assert MyDomainClass.getAll().isEmpty() // true
def myDomainClass1 = new MyDomainClass( some: "foo", arbitrary: 1, field: true)
assert MyDomainClass.getAll().contains(myDomainClass1); // false
myDomainClass1.save(flush:true)
def myDomainClass2 = new MyDomainClass( some: "bar", arbitrary: 1, field: true)
assert MyDomainClass.getAll().contains(myDomainClass2); // false. Even though this has the same `arbitrary` value as myDomianClass1, it has a different `some` value which makes it unique.
myDomainClass2.save(flush:true)
def myDomainClass3 = new MyDomainClass( some: "foo", arbitrary: 1, field: false)
assert MyDomainClass.getAll().contains(myDomainClass3); // false. Even though this has the same `some` value as myDomainClass1 and the same `arbitrary` value as myDomainClass1 and myDomainClass2, it has a different `field` value which makes it unique.
myDomainClass3.save(flush:true)
arbitrary unique: true
??? In this case it would help to provide the actual example you are working with. – James Kleeharbitrary unique: true
it would mean that no otherarbitrary
field in any other instance of thatMyDomainClass
could have the same value. That isn't what I want. I want other instance ofMyDomainClass
to be able to have the exact samearbitrary
value, so long as the values of other fields make the instance of the domain class unique. I will add a better example to illustrate that. – ubiquibaconsome unique: ['arbitrary', 'field']
– James Kleehunique
(I think that is what you are suggesting) I would have to do that for each field inMyDomainClass
. Example:some(unique:['arbitrary', 'field']
thenarbitrary(unique: ['some', 'field'])
thenfield(unique:['some', 'arbitrary'])
. I'm pretty sure this would get me what I want (and it is definitely more efficient than how I'm doing it now), but I would like a more generic solution if possible. – ubiquibacon