grails:如何在bootstrap中保存域对象,并通过忽略唯一约束错误来避免重复?

时间:2015-01-12 14:42:04

标签: grails bootstrapping

我们在bootstrap中创建了大量数据。 如果你这样做

 def foo = new Foo(bar:"hello").save(failOnError:true)

然后在测试环境中启动应用程序,其中包含" dbCreate ="更新" 和bar必须是唯一的,然后在尝试创建同一条数据的2个副本时会出错。

只调用save()而不使用failOnError可以部分地解决问题,因为现在它在数据库中创建了对象(如果它不存在),如果它已经存在则忽略它(假设至少有一个唯一约束来保护它)对象)。

但是,这不是站得住脚的,因为它没有告诉你是否还有其他错误,例如:

def foo = new Foo(barTypo:"hello").save()

并且您最终没有数据库中的数据,并且应用程序以意想不到的方式崩溃。

冗长的解决方案是在每次保存之前进行查找:

def foo = Foo.findByBar("hello")?: new Foo(bar:"hello").save(failOnError:true)

但是,我试图找到一种不那么冗长的方式。

我试过了:

saveIgnoreDups(new foo(bar:"hello"))

def saveIgnoreDups(ob) {
    try {
        ob.save(failOnError: true)
    } catch(org.springframework.dao.DataIntegrityViolationException e) {
        // fail silently - was already there.
    }
}

但这并不起作用:捕获不会捕获唯一的完整性约束失败。

我确信有一种简单的方法可以做到这一点,但不知道在哪里可以找到它。

有什么想法吗?

4 个答案:

答案 0 :(得分:1)

我强烈建议您在尝试保存之前使用.validate()进行调查,以验证您的域类实例有效

例如:

// Bootstrap.groovy
def foo = new Foo(bar:"hello")
if (foo.validate()) {
  foo.save()
} else {
 // maybe do something? maybe not. up to you.
}

以上对.vaidate()的来电将确保您的Foo对您定义的任何约束有效(例如,唯一bar)。

答案 1 :(得分:1)

你可以这样写:

Foo foo = new Foo(barTypo: "hello").save()

boolean hasTypoError = foo.hasErrors() && foo.errors.hasFieldError("barType")
boolean hasUniqueError = hasTypoError && foo.errors.getFieldError("barTypo").find {
    it.code == "default.not.unique.message" || it.code.contains("unique")
}

if (hasUniqueError ) {
    // your code 
}

答案 2 :(得分:0)

Joshuas的建议:

 def foo = Foo.findOrSaveWhere(bar:"hello")

似乎很好地解决了数据创建问题:如果它不存在则插入行,如果存在则读取它(奖励),最重要的是,如果存在字段错误,拼写错误或者抛出异常类似(比如有failOnError:true)

编辑 - 它没有捕获缺少必需的参数,并且默默地不保存对象,所以回到绘图板。

答案 3 :(得分:0)

试一试。从一个方法开始(或者在我的例子中是一个闭包):

def a = saveIgnoreDups(Foo, [bar:"hello"])
def b = saveIgnoreDups(Foo, [bar:"hello"])

第一个参数是域类,第二个参数是您要初始化实例的属性/值。它是这样用的:

public class MongoDbController : ApiController
    {         
        private static List<Db> _dbs = new List<Db>
        {
            new Db {id = 1, name = "Mongo"},
            new Db {id = 2, name = "AliExpress"},
            new Db {id = 3, name = "Herbal"}
        };

        [HttpGet]
        public HttpResponseMessage GetDbs()
        {
            var response = Request.CreateResponse(HttpStatusCode.OK, _dbs.ToArray());
            response.Headers.Add("Access-Control-Allow-Origin", "*");
            response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
            return response;
        }

        [HttpGet]
        public HttpResponseMessage GetDb(int id)
        {
            var db = _dbs.FirstOrDefault(d => d.id == id);
            if (db == null)
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, String.Format("Db with ID {0} not found", id));

            var response = Request.CreateResponse(HttpStatusCode.OK, db);
            response.Headers.Add("Access-Control-Allow-Origin", "*");
            response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
            return response;
        }

        [HttpPut]
        public HttpResponseMessage Put([FromBody] Db db)
        {
            var dbToUpdate = _dbs.FirstOrDefault(d => d.id == db.id);
            if (dbToUpdate == null)
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, String.Format("Db with ID {0} not found", db.id));

            dbToUpdate.name = db.name;

            var response = Request.CreateResponse(HttpStatusCode.OK, dbToUpdate);
            response.Headers.Add("Access-Control-Allow-Origin", "*");
            response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
            return response; 
        }

        [HttpPost]
        public HttpResponseMessage Post([FromBody] Db db)
        {           
            var dbToCreate = new Db
            {
                id = _dbs.Count() + 1,
                name = db.name
            };

            _dbs.Add(dbToCreate);

            var response = Request.CreateResponse(HttpStatusCode.OK, dbToCreate);
            response.Headers.Add("Access-Control-Allow-Origin", "*");
            response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");           
            return response;           
        }        
    }

在此示例中, b 将无法保存并抛出 grails.validation.ValidationException