How can I use more than one set of constraints on a single domain class in Grails? - grails

I need to choose a set of validation rules at save time. Ideally I would like to be able to define more than one set of constraints in the domain class:
class Account {
...
static constraints = { ... }
static constraints2 = { ... }
}
I know I can do my own validation in code (account.errors.rejectValue(...) etc) but I am looking to save some time by using the built in Grails validation if possible.

This is what Command Objects are for.
The reason you can't just swap out validation is that the validation also helps define the database structure, like setting a field to be non-null, or non-blank, or having a specific length. Turning off "non-null", for example, could break the database structure.
Command objects, on the other hand, are designed to have their own unique set of validation rules. It's not the cleanest method (now you are tracking the same structure in more than one situation), but it's better in a lot of ways.
It allows you to securely accept input parameters without worrying that something that shouldn't be processed gets set.
It creates cleaner controllers, since the validation logic can all be handled within the Command Object, and not sprinkled through the controller method.
They allow you to validate properties that don't actually exist on the object (such as password verification fields).
If you think you really need multiple sets of constraints, you are most likely either a) over-complicating the domain object to represent more information than it really should (maybe break it up into several one-to-one related objects), or b) incorrectly setting the constraints in the first place.†
In my experience, usually it's a that happens when you feel the need to swap out constraints.
† That being said, it can (rarely) make sense. But Command objects are the best solution in this situation.

you can use the validator constraint, see: http://www.grails.org/doc/latest/ref/Constraints/validator.html
within one validator constraint you can perform more checks than one and return diffrent error codes, e.g.
static constaints = {
name: validator { value, obj ->
if (value.size() > 10)
return [invalid.length]
else if (value.contains("test"))
return [invalid.content]
return true
}
in message.properties
domainClass.propName.invalid.content = ...
}

Related

Grails dynamic "inList"

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.

Modifying Grails constraints during runtime

The problem:
In my web application I defined some constraints. That I can save the domain class to "drafts" also when the constraint properties are not matching I set the constraint nullable to true. In the following process I can modify the object and after that to finalize the process I want to make a full validation. That means I want to add the nullable:false property.
Question 1: Is there a way to extend/ change constraints during the runtime?
Question 2: Is there a way to iterate through all constraints also when a domain class has nested constraints (e.g. other domain class references)
Thanks
Answer 1: Yes you probably can.
Answer 2: Yes.
So example:
def user = new User()
for(constraint in user.constraints) {
constraint.value.setBlank(true)
constraint.value.setNullable(false)
}
For nested fields:
for(constraint in user.someNestedFields.constraints) {
....
}
But i would not recommend to do so. It looks like bad architecture.
To save your domain entity without validation just call save(false).

MVC FluentValidation with entity framework in separate .dll

I have a separate .dll with our database model and partial classes etc in using FluentValidation which works fine (it's to be used by both by desktop barcoding terminals and also by our website).
For the desktop apps I can read and display all errors like below
public override int SaveChanges()
{
var errors = this.GetValidationErrors();
if (errors.Any())
{
//handle validation errors
return 0;
}
else
{
return base.SaveChanges();
}
}
For the MVC site I can set up validators on individual models or create data annotations and get those working okay (which is not what I want). The thing I can't get my head around is how I can force my models to map to my entities in a way that I can display the fluent validation messages in the views. I don't want to have two separate sets of logic to be maintained and the barcoding apps and website must use the same.
Do I have to map my entities directly to the views? which i've been led to believe is a bad thing and not very flexible. Or is there a way of stating that a field in a model maps back to an attribute of one of my entities? perhaps an annotation of some description.
EDIT:
Just some clarification for the types of validation i'll need.
most front end input type validation will still stay in the viewModels (required/length/password matches etc - basically all the stuff I can use for client side validation as well). But there are all the business logic validations that I don't want there. Things like email addresses must be validated before other options can be set, account numbers must be of a particular format based on name (stuff I can't do with a regex). This particular date is not a valid delivery date etc.
I guess one thing I could do is add these to the ValidationSummary somehow and display them separate from the individual fields.
I think you're just looking at the situation wrong. What MVC is all about is a separation of concerns. There's things the database needs to know about that your views could care less, and vice versa. That's why the recommended practice is to use view model with your views and not the entity itself.
Validation is much the same. Something like the fact that a password confirmation needs to match the password the user entered does not concern the database at all. Or more appropriately, something like a validation on minimum amount of characters in the password does not concern the database, either; it will only ever receive a salted and hashed version of the password. Therefore it would be wrong to put this kind of validation on your entity. It belongs on the view model.
When I first started out using MVC, I used to add all the validation logic to my entity class and then go and repeat that same validation on my view model. Over time, I started to realize that very little of the validation actually needs to be on both. In fact, the largest majority of validation will should just go on your view model. It acts as a gatekeeper of sorts; if the data is good enough to get through your view model, it's good enough for your database. The types of validation that make sense on your entity is things like Required, but even that is really only necessary on a nullable field that must have a value by the time it gets to your database. Things like DateTimes are non-nullable by default, and EF is smart enough to make them non-nullable on the tables it creates by default. MaxLength is at times worthwhile if there should be a hard limit on the length of a text field in your database, but more often than not, nvarchars work just fine.
Anyways the point is that if you actually sit down and start evaluating the validation on your entity, you'll likely see that most of it is business logic that only applies to how your application works and not to how the data is represented at the database level. That's the key takeaway: on your entity, you only need the validation that's necessary for the database. And that's generally pretty thin.
Just an update. to get the two tier validation that i needed i had to mark all my entity model classes as IValidatable. Then i overrode the validate method for each class and invoked my fluent validation validator method there, passing back the errors needed. for the modelstate.addmodelerror i set the key as the field name and it mapped back okay. bit more code but it works. if i find a better way to do this ill update.

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?
Do it as a custom constraint.
static constraints = {
childNodes(validator: {value, obj, errors->
if(value.contains(obj) {
errors.rejectValue('childNodes', 'Cannot contain self')
}
}
}
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:
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.
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.

Grails Domain Classes in Sets

Is it a bad practice to use domain objects in Sets or as keys in Maps?
In the past I've done things like this a lot
Set<Book> someBooks = [] as Set
someBooks.addAll (Book.findAllByAuthorLike('%hofstadter%'))
someBooks.add (Book.findByTitleLike ('%eternal%'))
However I have noticed that I often encounter problems when findAllByAuthorLike might return a list of Hibernate Proxy objects com.me.Book_$$_javassist_128 but findByTitleLike will return a proper com.me.Book object. This causes duplicates in the set because the real object and the proxy are considered not equal.
I find I need to be extremely careful when using Sets of domain objects like this, and I get the feeling it might be something I should not be doing in the first place.
The alternative is of course to use a set/map of id's, but it makes my code verbose and prone to misunderstanding
Set<Integer> someBooks = [] as Set // a set of id's for books
#Burt: I thought Grails domain classes already did this, at least so that equals/compare was done on class/id's rather than the object instance. Do you mean a special comparator for hibernate proxies?
return (this.class == obj.class && this.id == obj.id) ||
(obj.class == someHibernateProxy && this.id == obj.id)
It's not bad practice at all, but just like in a non-Grails application you should override equals and hashCode if you'll be putting them in hash-based collections (HashSet, HashMap, etc.) and also implement Comparable (which implies a compareTo method) if you're going to use TreeSet/TreeMap/etc.
Proper implementation of equals() and hashcode() in a Hibernate-backed situation is far from trivial. Java Collections require that hashcodes of objects and behaviour of equals() don't change, but the id of an object can change when it's a newly created object, and other fields can change for a wide variety of reasons. Sometimes you have a good unchangeable business id that you can use, but quite often that's not the case. And obviously default Java behaviour is also not suitable in a Hibernate situation.
The best solution I've seen is described here: http://onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html?page=2
The solution it describes is: initialize the id as soon as the object is created. Don't wait for Hibernate to assign an id. Configure Hibernate to use version to determine whether it's a new object. This way, id in unchangeable, and can be safely used for hashcode() and equals().

Resources