JPA多对多关系下实体复制异常求助:仅Employee表新增条目
问题:JPA复制Employee实例时,Address表未生成新条目
我有一个和Address类存在ManyToMany关联的Employee实体,现在想通过修改name属性来创建该实例的新数据库条目。执行代码后,Employee表成功新增了记录,但Address表却没有生成对应的新条目,麻烦帮忙排查一下问题!
实体类代码
Employee.java
@Entity @Table(name = "employee") public class Employee { public Employee() { super(); } public Employee(String name, List<Address> address) { super(); this.name = name; this.setAddress(address); } @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; private String name; @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.REMOVE,CascadeType.DETACH },fetch=FetchType.EAGER) @JoinTable(name = "employee_address", joinColumns = { @JoinColumn(name = "employee_id") }, inverseJoinColumns = { @JoinColumn(name = "address_id") }) private List<Address> address; @OneToOne private Department department; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public List<Address> getAddress() { return address; } public void setAddress(List<Address> address) { this.address = address; } public Department getDepartment() { return department; } public void setDepartment(Department department) { this.department = department; } }
Address.java
@Entity @Table(name = "Address") public class Address { public Address() { super(); } public Address(String address) { super(); this.address = address; } @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; private String address; @ManyToMany(mappedBy = "address", cascade = CascadeType.REMOVE) private List<Employee> employee; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
业务逻辑代码
DataRetrivalServiceImpl.java
@Service public class DataServiceImpl { @Autowired private EntityManager entityManager; @Transactional public void copyEmpoyee() { Employee e = employeeRepo.findOneById(15); entityManager.detach(e); e.setId(0); e.setName("new Name"); //employeeRepo.save(e); entityManager.persist(e); } }
问题原因分析
你遇到的核心问题是:从数据库查询出来的Address实例是已持久化状态的实体,即使你detach了Employee,这些Address对象的ID已经存在于数据库中。当你persist新的Employee时,Hibernate会识别到这些Address是已存在的记录,只会在中间表employee_address中创建新的关联关系,而不会在Address表中插入新条目——这完全符合JPA的持久化规则,因为CascadeType.PERSIST只会对**未持久化(transient状态)**的实体生效,对已有的managed或detached状态的实体不会触发插入操作。
解决方案
如果你确实需要为新的Employee创建对应的新Address条目,而不是复用已有的Address,你需要手动复制Address实例,生成新的transient状态的Address对象,再关联到新的Employee上。修改后的代码如下:
@Service public class DataServiceImpl { @Autowired private EntityManager entityManager; @Autowired private EmployeeRepo employeeRepo; // 确保注入Repository @Transactional public void copyEmpoyee() { Employee e = employeeRepo.findOneById(15); entityManager.detach(e); e.setId(0); e.setName("new Name"); // 复制原Address列表,创建新的Address实例 List<Address> newAddresses = new ArrayList<>(); for (Address originalAddr : e.getAddress()) { Address newAddr = new Address(); newAddr.setAddress(originalAddr.getAddress()); // 复制地址内容 newAddr.setId(0); // 重置ID,让JPA自动生成新ID newAddresses.add(newAddr); } e.setAddress(newAddresses); // 替换为新的Address列表 entityManager.persist(e); } }
这样处理后,新的Address实例是transient状态(没有数据库ID),当你persist新Employee时,CascadeType.PERSIST会触发这些新Address的插入操作,同时在中间表中创建新的关联记录。
内容的提问来源于stack exchange,提问作者Sunny
相关产品推荐
相关产品推荐

