我有一个实体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;
}
使用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;
}
在这种情况下, 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();
}
,mergeMXGroup
为:
@Override
public void mergeMXGroup(MXGroup group) {
super.merge(group);
}
其super
实现如下:
protected <T> T merge(T entity) {
if (canUseService() && beforeMergeEntity(entity)) {
T merge = this.getEntityManager().merge(entity);
return merge;
}
return null;
}
最后我强制刷新一个这样的提交:
public void forceCommit() {
this.getEntityManager().getTransaction().commit();
this.getEntityManager().flush();
}
RESTful接口几乎肯定会有一个与删除代码不同的实体管理器,因为删除代码是CDI管理的,RESTful接口是EJB。但是我会认为flush和commit会解决这个问题吗?事实上,这是我第一次在整个项目中明确刷新/提交......
有什么想法吗?
答案 0 :(得分:1)
我正在审查有关合并操作语义的规范。
这些情景中的任何一个都可能解释您的问题的原因(或许不是):
应用于实体X的合并操作的语义为 如下:
- 如果X是分离的实体,则将X的状态复制到预先存在的管理实体实例X&#39;相同的身份或新的 管理副本X&#39;创建了X.
- 如果X是新的实体实例,则新的管理实体实例X&#39;已创建,并且X的状态将复制到新的管理实体实例X&#39;。
- 如果X是已删除的实体实例,则合并操作将抛出IllegalArgumentException(或者事务提交将失败)。
- 如果X是一个托管实体,合并操作会忽略它,但是,如果这些关系已使用级联元素值cascade = MERGE注释,则合并操作将级联到由X关系引用的实体。 cascade = ALL注释。
- 如果X是合并到X&#39;的实体,引用另一个实体Y,其中未指定cascade = MERGE或cascade = ALL,则从X&#39;中导航相同的关联。产生对托管对象Y&#39;具有与Y
相同的持久性标识持久性提供程序不得合并尚未提取的标记为LAZY的字段:合并时必须忽略此类字段。
答案 1 :(得分:0)
我很确定,这不是你的问题的解决方案,但我必须补充一点,你的forceCommit()工作顺序错误。
首先,您必须使用flush()写入数据库,然后提交事务。 (也就是说,如果你需要同花顺。)