【问题标题】:Using Hibernate/EntityManager to update item required to have unique value使用 Hibernate/EntityManager 更新需要具有唯一值的项目
【发布时间】: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 进行实时运行和测试时也会发生这种情况。

我该如何解决这个问题?在执行任何修改/持久性之前,我是否需要引入一个检查提议的名称的业务层?

【问题讨论】:

标签: java spring hibernate jpa junit


【解决方案1】:

是的,您应该在修改前检查,而不是先修改后检查。 无论如何,这样更合乎逻辑,不是吗?

也就是说,您还应该在数据库中设置唯一约束,因为这是实际防止重复名称的唯一方法。使用唯一的约束,您会得到一个异常(虽然是一个不同的),即使您的行为方式也是如此。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-16
    • 1970-01-01
    • 1970-01-01
    • 2018-09-07
    • 1970-01-01
    • 1970-01-01
    • 2012-07-28
    相关资源
    最近更新 更多