如何添加验证以限制正在创建的行数

时间:2016-12-28 16:08:26

标签: validation grails grails-domain-class

我有一个Grails域类。我想添加一个验证,当应用程序在TEST环境中运行时,域类不能有超过100条记录。

我无法找出添加此类验证的最佳方法。我在Grails 2.5.3上。

这是我到目前为止所做的。

class MyDomain {

String test

static constraints = {
   test blank: false, nullable: false
   id blank: false, validator: {value, command -> 
      if (Environment.current == Environment.TEST) {
          //do validation for not allowing more than 100 records
      }
   }
}

如何添加此验证?

2 个答案:

答案 0 :(得分:2)

这样的事情会不适合你呢?

<iframe ng-if="mergedPdfFile" ng-src="{{mergedPdfFile}}" ...></iframe>

答案 1 :(得分:2)

单个域的解决方案

@Joshua的回答非常好,但还有其他一些方法。其中之一是:

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
    }
}

另外,请注意两件事:

  1. blank: false字段上的id没有用,因为它不是字符串,因为blank约束适用于字符串
  2. nullable: false没有用,因为nullable约束的默认值为false
  3. 跨域TL的通用解决方案; DR

    如果您希望在多个域中使用此行为,则不建议复制相同的代码,因为您的代码不会是DRY。为此,您可以注册自定义事件监听器:

    首先在src/groovy中定义Java注释:

    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
    }
    

    现在定义另一个Groovy类:

    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
        }
    }
    

    现在在Bootstrap.groovy注册:

    application.mainContext.eventTriggeringInterceptor.datastores.each { k, datastore ->
            applicationContext.addApplicationListener new PreInsertEventListener(datastore)
        }
    

    现在,在您的域中,您所要做的就是:

    @LimitRowsFoo
    class MyDomain {
    
        String test
    
        static constraints = {
            test blank: false
        }
    }
    
    @LimitRowsFoo(value = 200)   // to limit records to 200
    class MyAnotherDomain {
    
        String name
    }