如何添加验证以限制正在创建的行数
How to add validation to limit number of rows being created
我有一个 Grails 域 class。我想添加一个验证,以便当应用程序在 TEST 环境中为 运行 时,域 class 不能有超过 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
}
}
}
如何添加此验证?
像这样的东西对你有用吗?
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
if (MyDomain.count() > 100) return ['too.many.records']
}
}
}
单个域的解决方案
@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
}
}
此外,请注意两件事:
id
字段上的 blank: false
没有用,因为它不是字符串,因为 blank
约束适用于字符串
nullable: false
没有用,因为 nullable
约束的默认值是 false
跨域通用解决方案 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 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
}
}
现在在 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
}
我有一个 Grails 域 class。我想添加一个验证,以便当应用程序在 TEST 环境中为 运行 时,域 class 不能有超过 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
}
}
}
如何添加此验证?
像这样的东西对你有用吗?
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
if (MyDomain.count() > 100) return ['too.many.records']
}
}
}
单个域的解决方案
@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
}
}
此外,请注意两件事:
id
字段上的blank: false
没有用,因为它不是字符串,因为blank
约束适用于字符串nullable: false
没有用,因为nullable
约束的默认值是false
跨域通用解决方案 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 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
}
}
现在在 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
}