我们在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.
}
}
但这并不起作用:捕获不会捕获唯一的完整性约束失败。
我确信有一种简单的方法可以做到这一点,但不知道在哪里可以找到它。
有什么想法吗?
答案 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 。