I have 2 domain classes
class a {
String name
static constraints = {
name unique:true
}
}
class b {
String description
}
and in domain class b I want to call class a
import a
class b {
String description
static constraints = {
description unique:'a.name'
}
}
and get error
Scope for constraint [unique] of property [description] of class [b] must be a valid property name of same class
How do I get a property from class a to b?
Assuming you try to do this in Grails 2+
You can't use validation that way. In your example you need to reference to a property of the same domain class. To correct the constraint in class B you can write:
class B {
String description
static contraints = {
description unique:true
}
}
But I think you want to import the constraints from class a which is done like this.
class B {
String description
static contraints = {
importFrom A
}
}
See http://grails.org/doc/latest/guide/validation.html#sharingConstraints
This will import all constraints on properties that the two classes share. Which in your case is none.
UPDATE
I got a similar question and found a solution for it. So I thought to share it here with you.
The problem can be solved with a custom validator. In your case constraints for class B:
static constraints = {
description(validator: {
if (!it) {
// validates to TRUE if the collection is empty
// prevents NULL exception
return true
}
def names = A.findAll()*.name
return names == names.unique()
})
}
It's difficult to answer your question correctly since the requirements are a bit odd. But maybe it will help.
You need to write a custom validator to check the uniqueness since it relies on more information than the single instance of b will have.
Something like
static constraints {
description validator: { val ->
!a.findByName(val)
}
}
might do the trick.
Related
I have a trait and the following domain classes:
trait Named {
String name
static constraints = {
name blank:false, unique:true
}
}
#Entity
class Person implements Named {
String fullName
static constraints = {
fullName nullable:true
}
}
#Entity
class Category implements Named {
}
In this setup the Named.constraints are working fine for Category, but are ignored for Person.
How can I include the constrains from a trait in a constraints block of an implementing domain class?
How can I include the constrains from a trait in a constraints block
of an implementing domain class?
The framework doesn't support it.
I found the least painful way to re-use the constraints.
I added a new class:
class CommonConstraints {
static name = {
name blank:false, unique:true
}
}
Then instead of importFrom Named which didn't work, I sprinkle some groovy magic:
#Entity
class Person implements Named {
String imgUrl
String fullName
static constraints = {
CommonConstraints.name.delegate = delegate
CommonConstraints.name()
fullName blank:false, unique:true
imgUrl url:true
}
}
And it works like charm.
Yes, the solution not consistent with inheritance/implementation model, but gets the job of code reuse done.
For the less tricky cases, where the domain class does not have it's own constraints, the ones from a trait will be used, like in my original question.
I have a grails domain class with an embedded object, I want to validate the embedded object's attributes only while updating.
I know I can do this on a normal grails domain class by using a custom validator and checking if the domain's class id is not null.
I can't do this because of the lack of an id on an embedded object.
There is a little example of what I want to do.
//This is on domain/somePackage/A.groovy
class A{
B embeddedObject
static embedded = ['embeddedObject']
static constraints = {
embeddedObject.attribute validator:{val, obj-> //The app fails to start when this code is added!!
if(obj.id && !val) //if the id is not null it means the object it's updating...
return 'some.error.code'
}
}
}
//this class is on src/groovy/somePackage/B.groovy
class B{
String attribute
static constraints={
attribute validator:{val,obj->
if(obj.id && !val) //This will fail too! because the lack of an id on this object....
return 'some.error.code'
}
}
}
Is there a way to get the id of the 'parent' on the embedded object??
Any help will be appreciated
way too complicated:
class A{
B embeddedObject
static embedded = ['embeddedObject']
static constraints = {
embeddedObject validator:{ val, obj ->
if( obj.id && !val.attribute )
return 'some.error.code'
}
}
}
If I have a class with many properties that share identical attribute constraints like this:
class myClass {
String thisString
String thatString
String theOtherString
static constraints = {
thisString(nullable: true)
thatString(nullable: true)
theOtherString(nullable: true)
}
}
Is there an easier "one line" way to declare the static constraints? Something akin to say:
static constraints = {
thisString, thatString, theOtherString(nullable:true)
}
? Thank you.
Grails has something known as Global Constraints. This allows you to reuse identical constraints between many different GORM objects.
grails-app/conf/Config.groovy
grails.gorm.default.constraints = {
mySharedConstraint(nullable:true, ...)
}
myClass.groovy
class myClass {
String thisString
String thatString
String theOtherString
static constraints = {
thisString(shared: mySharedConstraint)
thatString(shared: mySharedConstraint)
theOtherString(shared: mySharedConstraint)
}
}
If you don't even want to to that...you can simply apply constraints to everything by doing something like this:
grails.gorm.default.constaints = {
'*'(nullable:true)
}
The start will apply this to all properties.
In the end, I would consult the link above. Good Luck!
Let's say I have the following model:
class Product {
String name
String price
String currency
static constraints = {
currency inList: ['USD', 'EUR']
}
Now we have a new requirement that inList constraint for currency must be pulled from a service:
class CurrencyService {
def getAvailableCurrencies = {
...
}
}
How do I make this work? I tried:
class Product {
def currencyService
...
static constraints = {
currency inList: currencyService.getAvailableCurrencies()
}
}
But I can't access the currencyService instance in the static constraints context. I also tried using static currencyService, but this likewise does not work. Any ideas?
As dmahapatro mentioned above, you could use a custom validator which uses your service:
static constraints = {
currency validator: { value, obj ->
if (!(value in obj.currencyService.getAvailableCurrencies()))
return ['invalid.currency']
}
}
I need to create a many-to-many relationship in Grails.
I have a "Question" domain and a "Tag" domain.
A Question can have 0 or more tags. A Tag can have 0 or more Questions.
If I put a "hasMany" on each sides, it gives me an error saying I need a "belongTo" somewhere.
However, adding a belongsTo means that the owner must exist...
Like I said, a Tag could have 0 questions, and a Question could have 0 tags.
There is no concept of an owner, it's a many-to-many!
What am I supposed to do?
you can do this (please see the code below). but does it make sense to have a question tag with out both a question and a tag?
package m2msansbt
class Question {
String toString() { return name }
String name
static hasMany=[questionTags:QuestionTag]
static constraints = {
}
}
package m2msansbt
class Tag {
String toString() { return name }
String name
static hasMany=[questionTags:QuestionTag]
static constraints = {
}
}
package m2msansbt
class QuestionTag {
Question question
Tag tag
static QuestionTag link(Question question,Tag tag) {
QuestionTag questionTag=QuestionTag.findByQuestionAndTag(question,tag)
if (!questionTag) {
questionTag = new QuestionTag()
question?.addToQuestionTags(questionTag)
tag?.addToQuestionTags(questionTag)
questionTag.save()
}
return questionTag
}
static void unlink(Question question,Tag tag) {
QuestionTag questionTag=QuestionTag.findByQuestionAndTag(question,tag)
if (questionTag) {
question?.removeFromQuestionTags(questionTag)
tag?.removeFromQuestionTags(questionTag)
questionTag.delete()
}
}
static constraints = {
}
}
import m2msansbt.*
class BootStrap {
def init = { servletContext ->
Question q1=new Question(name:'q1')
Tag t1=new Tag(name:'t1')
Tag t2=new Tag(name:'t2')
q1.save()
t1.save()
t2.save()
QuestionTag q1t1=QuestionTag.link(q1,t1)
q1t1.save()
QuestionTag q1t2=QuestionTag.link(q1,t2)
q1t2.save()
q1.save()
t1.save()
}
def destroy = {
}
}
If your main concern is the cascading delete, you can take a look at 5.5.2.9 in the grails docs to manually disable it for the mapping.
I haven't tried it, but I think the mappedBy property can be used to solve this.
Checkout the Taggable Plugin.
It seems to solve the problem you are having and you could look at the source code if you want to see how they modeled the relationship. BTW this plugin was originally created by Graeme Rocher who is the lead developer on Grails.
This works for me on Grails 2.4.4. Add a "belongsTo" with just the classname.
class Question {
String toString() { return name }
String name
static hasMany=[tags:Tag]
static constraints = {
}
}
class Tag {
String toString() { return name }
String name
static hasMany=[questions:Question]
static belongsTo = Question
static constraints = {
}
}