Solution for a single domain
What @Joshua answered is perfectly fine but there are few other ways. One of them is:
class MyDomain {
String test
void beforeInsert() {
if (Environment.current == Environment.TEST) {
MyDomain.withNewSession {
if (MyDomain.count() == 100) {
throw new Exception("Not allowing more than 100 records")
}
}
}
}
static constraints = {
test blank: false
}
}
Also, please note two things:
- The
blank: false
on the id
field of no use since it is not a string because blank
constraint is applicable on a String
- The
nullable: false
is of no use since the default value of nullable
constraint is false
Generic solution for across domain TL;DR
If you want this behavior across multiple domains, copying the same code is not recommended as your code won't be DRY. For that, you can register a custom event listener:
First define a Java annotation in src/groovy
:
import java.lang.annotation.Documented
import java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target
@Documented
@Target([ElementType.TYPE, ElementType.FIELD])
@Retention(RetentionPolicy.RUNTIME)
public @interface LimitRowsFoo {
int value() default 100
}
Now define another Groovy class:
import grails.util.Environment
import org.grails.datastore.mapping.engine.event.PreInsertEvent
import org.grails.datastore.mapping.engine.event.AbstractPersistenceEvent
import org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener
class PreInsertEventListener extends AbstractPersistenceEventListener {
PreUpdateEventListener(final Datastore datastore) {
super(datastore)
}
@Override
protected void onPersistenceEvent(AbstractPersistenceEvent event) {
// Instance of domain which is being created
Object domainInstance = event.entityObject
if (Environment.current == Environment.TEST) {
if (domainInstance.class.isAnnotationPresent(LimitRowsFoo.class)) {
// Just using any domain reference here
MyDomain.withNewTransaction {
int maxRows = domainInstance.class.getAnnotation(LimitRowsFoo.class).value()
if (domainInstance.class.count() == maxRows) {
event.cancel()
}
}
}
}
}
@Override
boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
// Only allow PreInsert event to be listened
eventType.name == PreInsertEvent.class.name
}
}
Now register this in Bootstrap.groovy
:
application.mainContext.eventTriggeringInterceptor.datastores.each { k, datastore ->
applicationContext.addApplicationListener new PreInsertEventListener(datastore)
}
Now, in your domain, all you have to do is like these:
@LimitRowsFoo
class MyDomain {
String test
static constraints = {
test blank: false
}
}
@LimitRowsFoo(value = 200) // to limit records to 200
class MyAnotherDomain {
String name
}