This is almost identical to this old question: Dynamic define the inList constraint using database query which was essentially unaddressed, perhaps there have been advances in the years since that was asked.
I'd like to populate the inList parameter of a domain attribute with values from another domain. Due to auto-generated views (scaffolding, filterpane), this needs to come from inList rather than a custom validator.
class MyDomain {
String someValue
static constraints = {
someValue(nullable: true, maxSize: 50, inList: SomeOtherDomain.list()*.name)
}
}
This gives the following error on startup:
Caused by: java.lang.IllegalStateException: Either class [thepackage.SomeOtherDomain] is not a domain class or GORM has not been initialized correctly or has already been shutdown. Ensure GORM is loaded and configured correctly before calling any methods on a GORM entity.
I know, the "correct" way to handle this is to make someValue an instance of SomeOtherDomain instead of just storing the name, but that doesn't quite fit. We want to be able to delete an instance of SomeOtherDomain without breaking the saved value of the owning domain... the domain with the deleted value will be invalid going forward, and would have to be updated before saving, but archived/locked records will still exist and can be displayed.
You can specify value lists for filterpane like this:
<filterpane:filterPane domain="MyObject" filterPropertyValues="${['someValue':[values: SomeOtherDomain.list().collect{it.name}]]}" />
And then just use a custom validator to actually validate. I'm not sure what scaffolding might use the inList but easy enough to get around that if you're OK with replacing a few scaffolded pages with static ones.
Related
I've got a domain called Planning that has a hasMany of another domain called Employee included in it. I'm trying to do a findAll of these plannings where the plannings contain a particular employee and I can't get it to work.
I'm trying to do it like so, my print statements do print the contains as true
plannings = plannings.findAll{planning->
if(employee) {
log.info("find plannings with employee ${employee} ${planning.employees.contains(employee)}")
planning.employees.contains(employee)
}
}
I'm not doing this as a Hibernate query as this broke the application in another weird way. This code is executed in a for each and for whatever reason that causes some weird behavior with Hibernate.
The closure must return a boolean value - see http://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Collection.html#findAll(groovy.lang.Closure)
This should work (not tested):
plannings = plannings.findAll{planning-> planning.employees?.contains(employee)}
BTW: I wouldn't assign the filtered list to the origin plannings list. Extract a a new expressive variable like planingsOfEmployee or something similar.
Without more relevant details around your problem (what's the weird behavior? log traces? hibernate mappings?, etc.) all we can do is to speculate; and if I have to do so, I would say that most likely:
The employee object you are using for comparison is a detached one.
The employee object does not override meaningfully equals and hashCode
You use using this detached employee to do comparisons against against persisted employees (using planning.employees.contains(employee)) found inside planning
Under these circumstances the comparisons will never be true even when they may represent the same objects. If this is your case, you must either:
Use a persisted employee object to do the comparisons.
Or, implement equals and hashCode semantically meaningful for Employee
Hope this helps.
I am using grails 2.4.3 with database Neo4j with SDN ,We don't use Grails plugin so grails doesn't support Neo4j and if we create our domain classes in domain package then it gives us an error.
So We create our domain in Services package. My First Question is:
We are right or we have to do another thing?
My another question is to provide the validation in this concept. We use the Command Object for it. So now we need some Custom validation for unique. I know we can use Validator for it, but we want that our logic only remain in Services. So can we create something like this?
static constraints = {
username size: 5..15
password size: 5..15, blank: false
userEmail email: true
}
username email:true
userName name:unique
I don't understand why you're so fixated on having to use a service for this. Creating a service annotated with #Validateable and using it as a non-GORM domain class seems very weird. If it works, cool, but it's sort of like driving to work in reverse the whole way. You'll get there (until you burn out the transmission) but it'll be a stressful drive looking in the rear view mirror and seeing everthing reversed the whole time.
Why not just put the classes in a sensible package under src/groovy and annotate those? You just need to register them in Config.groovy, e.g.
grails.validateable.classes = [
com.mycompany.myapp.User, com.mycompany.dto.Account]
You can do a uniqueness check, but not with the standard unique constraint. That's tied to GORM; it looks at the table or backing store for you domain class and runs a datastore-specific uniqueness query, but that doesn't apply here. But you can easily do the same thing yourself. Use a custom validator:
email validator: { value, obj ->
// run a Neo4j query checking to see if value has
// been used, the equivalent of
// "select count(email) from person where email=?"
// and return false if the count is not zero
}
I am using grails GORM for database mapping and oracle as database which is already populated with values.My question is can I define a new constraint like Foreign key in the domain class even if its not defined in the underlying table in my legacy db?The grails app is still going to accept the constraints right?The constraints dont have to exactly match those of database right?
you can define attributes of a class, which are not saved in the db and due to this don't need a representation in the db these attributes are defined as follows:
class Person {
String name
static transients = ['name']
}
see information about transients. In 2.x transients are not auto-bound as listed in the docs here, so you have to do a bindable: true explicitly.
Yes, the constraints you define in your domain class will be respected regardless of what you have in your database. The only time the 2 really relate is if you are letting Hibernate generate DDL for you (which most folks do not do for their production environment) in which case there are certain constraints which affect the DDL that is generated. Since you already have a database you almost certainly have that turned off.
EDIT:
An example of a constraint which affects DDL is the size constraint. If you constrain a String field with something like size: 5..15, by default the DDL that is generated will create a column that is 15 characters wide. If you are not allowing the app to generate DDL that constraint is still applied at validation time and if the property has more than 15 characters or fewer than 5, validation will fail. Once validation passes and the data is sent to the database, the framework assumes everything will be ok there. If it isn't, then corresponding exceptions may be thrown. For example, if the String has 12 characters it will pass validation in the app and will be sent to the database. If the database column is only 8 characters wide, you are going to get a SQLException. I hope that makes sense.
Let's say I have classes similar to domain classes in my application with some Long, Double, Date and String fields. These classes extend base class with some common fields and few common methods. Whenever I access class field (though getter) that is String, I want to make some changes to the value returned (for example remove html tags). Is there a better way than making implementations of getters for each fields of String type? What about inherited fields?
Don't change default getter/setter implementations created for you by Grails. You would definitely mess up your application in various places. Grails uses convention over configuration so getters/setters should definitely remain unchanged.
Create your own methods that return what you want: for a field title create method getStrippedTitle(). You can add this method to transients too.
If you change the value that's set, or return a value that's different from what was set, you'll confuse Hibernate. That's because when you load an instance from the database, Hibernate keeps the original data in its 1st-level cache, and returns a domain object instance to you. When you flush, it compares the current state with the original, and if it changed, it will push the changes to the database. So if you return a different value than what was set, but don't really change the value, Hibernate can't tell the difference.
You're much better off leaving the properties alone and creating methods that return altered data. One convention I've used is that if for example you have a String body field, you can access it via the property name body or the getter getBody(), but you can create a body() method that's unknown to Hibernate and returns whatever you want.
Suppose I have a domain class branch which has several members:
…
static hasMany = [ members:Member ];
…
Now suppose I want to have the number of members of that branch readily available, to have it displayed in the list and view actions, so perhaps storing that information into a variable in the domain class itself would be a good idea?
…
Integer memberCount = members.size();
static constraints = {
memberCount(editable:false);
}
…
(Is this the correct syntax?) Edit: This is not the correct syntax. I cannot assess the size of the members list, as it doesn’t exist yet and grails will complain about size() not being applicable to null objects. What else could I try?
However, as memberCount is now a variable in the domain class, it is possible to assign a value to it upon creation of the Branch (which is contra-intuitive) and it will not be updated automatically once a new Member is added.
It is of course possible to reach the desired result in a different way. I could manipulate the view.gsp and list.gsp in the /Branch directory, add some additional <td>s there etc. But that does not seem very elegant to me.
Basically, I think what I am looking for is some way to tell grails that a certain variable is derived, should not be setable by the user, but update whenever necessary. Is there such way?
You can add any property you don't want persisted to the transients static list:
static transients = ['memberCount']
See this page in the manual
Also, this StackOverflow question answers the same question
Also, a better way to do derived properties may be to use the Derived Properties feature of GORM