【发布时间】:2016-08-25 17:12:39
【问题描述】:
我有一个使用 JPA 和 Hibernate 来跟踪 Recipe 对象列表的 Spring Boot 应用程序。我有少量成功的 JUnit 测试,我想围绕重命名配方添加一个新测试。
有一个业务要求,每个 Recipe 必须有一个唯一的名称。
相关代码sn-ps:
控制器:
@RequestMapping(value = "/recipe/{recipeId}", method = RequestMethod.PATCH)
@Transactional
public ResponseEntity<String> renameRecipe(@PathVariable Long recipeId,
@RequestParam(name = "name") String newRecipeName) {
Recipe recipe = recipeManager.get(recipeId);
recipe.setName(newRecipeName);
recipeManager.save(recipe);
return new ResponseEntity<>(recipe.toJSONString(), HttpStatus.OK);
}
经理:
@Repository
public class RecipeManager {
....
public Recipe save(Recipe recipe) {
System.out.println("save(): All recipes: " + getAll());
if (lookupByName(recipe.getName()) != null) {
throw new IllegalArgumentException("A recipe with this name already exists");
}
em.persist(recipe);
return recipe;
}
测试:
@Test
public void testRecipeCanBeRenamed() throws UnirestException {
HttpResponse<JsonNode> jsonResp = Unirest.post("http://localhost:" + port + "/recipe")
.field("name", "Spaghetti").asJson();
long recipeId = jsonResp.getBody().getObject().getLong("id");
jsonResp = Unirest.patch("http://localhost:" + port + "/recipe/" + recipeId).field("name", "Pesto Pasta")
.asJson();
jsonResp = Unirest.get("http://localhost:" + port + "/recipe/" + recipeId).asJson();
JSONObject recipeObj = jsonResp.getBody().getObject();
assertEquals(recipeId, recipeObj.getLong("id"));
assertEquals("PestoPasta", recipeObj.getString("name"));
assertNull(recipeManager.lookupByName("Spaghetti"));
assertNotNull(recipeManager.lookupByName("Pesto Pasta"));
}
测试的问题是IllegalArgumentException 被抛出,这是我认为是 Hibernate 的本地缓存机制的结果。当我在renameRecipe() 方法中对检索到的Recipe 实例调用setName() 时,它实际上是在更改本地缓存实例上的此属性。因此,当管理器尝试 save() 和 Recipe 时,它会授予其本地缓存,并看到 尚未持久化到数据库的 属性更改 .
在运行我的单元测试时,在 save() 方法中,在重复检查之前,我看到:
save(): All recipes: [{"name":"Pesto Pasta","id":1}]
通过 Postman 进行实时运行和测试时也会发生这种情况。
我该如何解决这个问题?在执行任何修改/持久性之前,我是否需要引入一个检查提议的名称的业务层?
【问题讨论】:
-
这不会解决您当前的问题,但会阻止新的问题:请注意,您的 save() 方法正在调用 EntityManager.persist(),它将尝试创建一个新的持久化实体,几乎肯定会抛出
EntityExistsException。鉴于您实际上想要更新一个现有实体 -> What is the best way to update the entity in JPA
标签: java spring hibernate jpa junit