You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:14:37