尽管刷新和事务提交,Hibernate实体属性仍未持久化到数据库

Mat*_*ows 6 merge hibernate jpa commit

我有一个MXGroup可以通过status属性逻辑删除的实体.该实体通过Hibernate持久存储到MySQL数据库中.当我通过我的JSF页面创建这个实体时,坚持下去,然后尝试更新该实体的status列而不在创建之间重新加载我的页面并在逻辑上删除它,状态列的更改不会持久化.

该实体显然位于Hibernate的缓存和数据库中.更新属性然后merge使用它调用不会将更改合并到数据库中.

我已经明确要求flush,并getTransaction().commit()在合并后的实体我的实体管理器,但仍然没有骰子.

如果我刷新我的页面(可能会EntityManager因为我EntityManagers的会话范围而变得不同),那么我可以突然删除我MXGroup没有任何问题.

我知道我可以做一些变通办法 - 所以这主要是为什么会发生这种情况的学术练习......

我的MXGroup实体通过ajax通过RESTful接口加载,具有以下方法:( PersonalGroup实体扩展MXGroup实体)

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("personal/")
public Response restPersonalGroups() {
    return Response.ok().entity(serializePersonalGroups()).build();
}

public String serializePersonalGroups() {
    final List<PersonalGroup> personalGroupsList = this.userGroupService.getPersonalGroups();
    String personalGroups = serializeGroupList(personalGroupsList);
    return personalGroups;
}
Run Code Online (Sandbox Code Playgroud)

用这个userGroupService.getPersonalGroups()方法看起来像:

public List<PersonalGroup> getPersonalGroups() {
    CriteriaBuilder builder = this.getEntityManager().getCriteriaBuilder();
    CriteriaQuery<PersonalGroup> criteria = builder.createQuery(PersonalGroup.class);
    Root<PersonalGroup> root = criteria.from(PersonalGroup.class);

    List<Predicate> predicateList = new ArrayList<Predicate>();
    predicateList.addAll(Arrays.asList(getCommonPredicates(PersonalGroup.class, builder, criteria, root)));
    predicateList.add(builder.equal(root.get(PersonalGroup_.user), getUser()));

    TypedQuery<PersonalGroup> query = this.getEntityManager().createQuery(
        criteria.select(root)
            .where(predicateList.toArray(new Predicate[predicateList.size()]))
            .orderBy(builder.asc(root.get(MXGroup_.name)))
            .distinct(true));

    List<PersonalGroup> personalGroups = query.getResultList();
    for (PersonalGroup pg : personalGroups) {
        this.getEntityManager().refresh(pg);
    }
    return personalGroups;
}
Run Code Online (Sandbox Code Playgroud)

getCommonPredicates 在这种情况下,只添加谓词检查是否 status == 1

删除功能如下所示:

public void deletePersonalGroup() throws BadLoginNameException, UniqueUserLoginException {
    String groupIdStr = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("groupId");
    int groupId = Integer.parseInt(groupIdStr);
    MXGroup group = this.userGroupService.findMXGroup(groupId);

    group.setStatus(0);
    this.userGroupService.mergeMXGroup(group);
    this.userGroupService.forceCommit();
}
Run Code Online (Sandbox Code Playgroud)

mergeMXGroup存在:

@Override
public void mergeMXGroup(MXGroup group) {
    super.merge(group);
}
Run Code Online (Sandbox Code Playgroud)

super实现如下:

protected <T> T merge(T entity) {
    if (canUseService() && beforeMergeEntity(entity)) {
        T merge = this.getEntityManager().merge(entity);
        return merge;
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

最后我强制刷新并像这样提交:

public void forceCommit() {
    this.getEntityManager().getTransaction().commit();
    this.getEntityManager().flush();
}    
Run Code Online (Sandbox Code Playgroud)

RESTful接口几乎肯定会有一个与删除代码不同的实体管理器,因为删除代码是CDI管理的,RESTful接口是EJB.但是我会认为flush和commit会解决这个问题吗?事实上,这是我第一次在整个项目中明确刷新/提交......

有什么想法吗?

Ish*_*Ish 1

我正在审查有关合并操作语义的规范。

以下任一情况都可以解释您的问题的原因(也可能不能):

应用于实体X的合并操作的语义如下:

  • 如果 X 是分离实体,则 X 的状态将复制到具有相同身份的预先存在的受管实体实例 X' 上,或者创建 X 的新受管副本 X'。
  • 如果X是新的实体实例,则创建新的被管理实体实例X',并且X的状态被复制到新的被管理实体实例X'中。
  • 如果X是一个被删除的实体实例,则合并操作将抛出IllegalArgumentException(或者事务提交将失败)。
  • 如果 X 是托管实体,则合并操作将忽略它,但是,如果这些关系已使用级联元素值cascade=MERGE 或cascade=ALL 注释进行注释,则合并操作将级联到X 中的关系引用的实体。
  • 如果 X 是合并到 X' 的实体,并引用另一个实体 Y,其中未指定cascade=MERGE 或cascade=ALL,则从 X' 导航相同的关联将产生对托管对象 Y' 的引用,其中与 Y 相同的持久身份

持久性提供程序不得合并尚未获取的标记为 LAZY 的字段:合并时必须忽略此类字段。