所以,我有2个实体项目& 任务计划,在项目实体内部, @ManyToMany 与 TaskPlan 实体关联
@Entity
@Table(name = "project")
public class Project {
@Column(name = "descriptions")
private String descriptions;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "project_has_task_plan",
joinColumns = {@JoinColumn(name = "project_id")},
inverseJoinColumns = {@JoinColumn(name = "task_plan_id")})
private Set<TaskPlan> taskPlans;
public Set<TaskPlan> getTaskPlans() {
return taskPlans;
}
public void setTaskPlans(Set<TaskPlan> taskPlans) {
this.taskPlans = taskPlans;
}
....
@Entity
@Table(name = "task_plan")
public class TaskPlan {
@GeneratedValue(generator = "idIncrementor")
@GenericGenerator(name = "idIncrementor", strategy = "increment")
@Id
private Long id;
@Column(name = "name")
private String name;
@Column(name = "description")
private String description;...
我使用DAO方法与两个实体交互,我有一个 @PersitenceContext(type = PersistenceContextType.EXTENDED)。我也使用泛型来通过id获取实体
public T getById (Long id) {
if (id==null) {
return null;
} else {
Query query = this.entityManager.createQuery("from " + type.getName() + " where id=:id");
query.setParameter("id", id);
List<T> result = query.getResultList();
if (!result.isEmpty()) {
return result.get(0);
}
throw new IllegalArgumentException("Not found!");
}
}
我正在使用以下方法更新Project实体上的taskplans集合,并向 taskPlans Set
添加新元素//ProjectService class
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
@ResponseBody
public void updateProject(@RequestBody Project project) throws Exception {
this.projectFacade.updateOne(project);
}
//ProjectFacade class
@Override
public void updateOne(Project project) {
Project itemFromDbs = this.projectDao.getById(project.getId());
if (itemFromDbs != null) {
itemFromDbs.setName(project.getName());
itemFromDbs.setDescriptions(project.getDescriptions());
if (project.getTaskPlans() != null) {
project.getTaskPlans().stream().forEach(taskPlan -> {
TaskPlan taskPlanToAdd = taskplanDao.getById(taskPlan.getId());
if (taskPlanToAdd == null) {
itemFromDbs.getTaskPlans().add(taskPlan);
}
});
}
this.projectDao.updateProject(itemFromDbs);
}
}
....
//ProjectDao class
@Transactional
public void updateProject(Project project) {
Project itemFromDbs = this.getById(project.getId());
if (itemFromDbs != null) {
itemFromDbs.setTaskPlans(project.getTaskPlans());
entityManager.getEntityManagerFactory().getCache().evictAll();
entityManager.persist(itemFromDbs);
entityManager.flush();
entityManager.clear();
}
}
目前一切正常,当我尝试从 TaskPlan 实体中移除任务计划时,会发生坏事。 .entitymanager.remove()工作正常,实体将从 TaskPlan表和关联的 project_has_task_plan 表中删除,但是当我刷新页面并 getById 项目实体触发 TaskPlan 实体中已删除的项目仍在设置任务计划 ...
我必须提到二级缓存已完全禁用且 clear()或 evictAll()方法无效。< / p>
以下是删除代码:
//TaskPlanService class
@RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
@ResponseBody
public void deleteTaskPlan(@PathVariable("id") Long taskPlanId) throws Exception {
this.taskplanFacade.deleteOne(taskPlanId);
}
//TaskPlanFacade class
public void deleteOne(Long taskPlanId) {
taskplanDao.deleteById(taskPlanId);
}
//TaskPlanDao class
@Transactional
@Override
public void deleteById(Long taskPlanId) {
TaskPlan taskPlanFromDbs=this.getById(taskPlanId);
if(taskPlanFromDbs!=null){
taskPlanFromDbs.getTasks().stream().forEach(task -> {//this things
//are associated with the
//taskplan entity but for the moment i don't interract
//with them
task.getBadges().stream().forEach(badge -> {
entityManager.remove(badge);
});
entityManager.remove(task);
});
taskPlanFromDbs.getBadges().stream().forEach(badge -> {
entityManager.remove(badge);
});
entityManager.remove(taskPlanFromDbs);
entityManager.flush();
entityManager.clear();
}
}
答案 0 :(得分:2)
作为开发人员,您负责维护实体的所有关系。因此,如果删除TaskPlan
,则必须注意将其从与其他实体的任何关联中删除。
JPA 2.1 Specification 2.9 EntityRelationships :
请注意,应用程序负责维护运行时关系的一致性 - 例如,确保双向关系的“一”和“多”方在应用程序更新时保持一致在运行时的关系。
答案 1 :(得分:0)
[披露:我没有调试过,试图执行甚至深度阅读你的代码;我不知道如何创建EntityManager或者你正在使用哪个@Transactional
Hibernate(以及其他JPA提供程序)通常在获取实体时不会修改实体 - 没有魔法附加到您的对象,您仍然可以自由使用自定义集合等。没有任何理由可以从中删除或出现在你的收藏中。
使用JPA的概念基于“工作单元”模式,该模式要求将操作拆分为单独的“业务逻辑块”,并在单独的EntityManager中运行每个块。只有当完成整个工作并且完成工作时,EntityManager关闭(至少在mental model中;实现工作方式不同),才会与数据库同步。
通过使用扩展的实体管理器,您展示的代码会将猴子扳手扔进机器中。消息来源似乎滥用了Hibernate,并且可能存在很多问题,既逻辑又与并发相关。通过使用普通的事务性实体管理器,可以很容易地修复和简化它。
答案 2 :(得分:0)
解决 我设置了@PersitenceContext(type = PersistenceContextType.TRANSACTION) 然后在ProjectDao类中:
@Transactional
public void updateProject(Project project) {
Project itemFromDbs = this.getById(project.getId());
if (itemFromDbs != null) {
itemFromDbs.setTaskPlans(project.getTaskPlans());
entityManager.merge(itemFromDbs);//so i wont persist a detached entity
entityManager.flush();
}
}
改变了项目&amp; TaskPlan实体asociation fetchType选项,所以我不会得到一个延迟的初始化错误:
@Entity
@Table(name = "project")
public class Project {
@GeneratedValue(generator = "idIncrementor")
@GenericGenerator(name = "idIncrementor", strategy = "increment")
@Id
private Long id;
@Column(name = "name")
private String name;
@Column(name = "descriptions")
private String descriptions;
@ManyToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
@JoinTable(name = "project_has_task_plan",
joinColumns = {@JoinColumn(name = "project_id")},
inverseJoinColumns = {@JoinColumn(name = "task_plan_id")})
private Set<TaskPlan> taskPlans;
谢谢@fdreger:)