首页 文章

JPA / Eclipselink如何处理循环/循环关系

提问于
浏览
1

我对JPA中的循环关系有疑问,特别是Eclipselink JPA实现 . 对不起,如果问题有点长,但我尽量保持精确 .

让我们来看一个Department和Employee的简单例子,其中一个部门有一对多的“雇员”关系(因此从员工到部门的反向多对一“部门”关系) . 现在让我们从部门向员工添加一对一的关系“经理”(该部门的一名员工是同一部门的经理) . 这引入了两个实体之间的循环关系,两个表都有一个引用另一个表的外键 .

我希望能够在不获取外键约束违规的情况下执行所有插入操作 . 所以,我的想法是先插入所有员工(不设置部门关系),然后插入部门(设置其经理),最后更新所有员工以设置他们的部门 .

我知道我可以使用 flush() 来强制插入执行的顺序,但我被告知应该避免它,因此想知道是否有办法告诉JPA / Eclipselink应首先插入Department,然后是Employee .

在Eclipselink中,我确实尝试将Employee添加为Department类的classdescriptor的约束依赖项,但它仍然随机给出错误 .

这是一个说明此问题的代码示例(问题随机发生):

系类:

package my.jpa.test;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Persistence;

/**
 * Entity implementation class for Entity: Department
 *
 */
@Entity
public class Department implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @OneToMany(fetch = FetchType.EAGER)
    private List<Employee> employees;

    @OneToOne
    @JoinColumn(name = "manager", nullable = false)
    private Employee manager;

    private static final long serialVersionUID = 1L;

    public Department() {
        super();
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public List<Employee> getEmployees() {
        return employees;
    }

    public void setEmployees(List<Employee> employees) {
        this.employees = employees;
    }

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("test-jpa");
        EntityManager em = emf.createEntityManager();
        Department d = new Department();
        Employee manager = new Employee();
        manager.setLastName("Doe");
        d.setManager(manager);
        Employee e1 = new Employee();
        e1.setLastName("Doe");
        Employee e2 = new Employee();
        e2.setLastName("Smith");
        em.getTransaction().begin();
        em.persist(d);
        manager.setDepartment(d);
        e1.setDepartment(d);
        e2.setDepartment(d);
        em.persist(e1);
        em.persist(e2);
        em.persist(manager);
        em.persist(d);
        manager.setDepartment(d);
        e1.setDepartment(d);
        e2.setDepartment(d);
        em.merge(manager);
        em.merge(e1);
        em.merge(e2);
        em.getTransaction().commit();
        em.clear();
        Department fetchedDepartment = em.find(Department.class, d.getId());
        System.err.println(fetchedDepartment.getManager().getLastName());
        System.err.println(new ArrayList<Employee>(fetchedDepartment.getEmployees()));
    }

    public Employee getManager() {
        return manager;
    }

    public void setManager(Employee manager) {
        this.manager = manager;
    }
}

员工类:

package my.jpa.test;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;

/**
 * Entity implementation class for Entity: Employee
 *
 */
@Entity
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String lastName;

    @ManyToOne
    private Department department;

    @OneToOne(mappedBy = "manager")
    private Department managedDepartment;

    public Employee() {
        super();
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }

    public Department getManagedDepartment() {
        return managedDepartment;
    }

    public void setManagedDepartment(Department managedDepartment) {
        this.managedDepartment = managedDepartment;
    }

    @Override
    public String toString() {
        return "Employee " + getLastName();
    }

}

persistence.xml中:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="test-jpa">
        <class>my.jpa.test.Department</class>
        <class>my.jpa.test.Employee</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE" />
            <property name="javax.persistence.jdbc.user" value="sa" />
            <property name="javax.persistence.jdbc.password" value="" />
            <property name="hibernate.hbm2ddl.auto" value="create-drop" />
            <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
            <property name="eclipselink.ddl-generation.output-mode" value="database" />
            <property name="eclipselink.logging.level" value="FINE"/>
            <property name="eclipselink.logging.parameters" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

Maven依赖:

<dependencies>
    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>eclipselink</artifactId>
        <version>2.5.1</version>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.3.172</version>
    </dependency>
</dependencies>

2 回答

  • 1

    恕我直言这个型号你真的没有选择 .

    • 插入部门(没有经理)

    • 插入员工(有部门)

    • 同花顺

    • 更新部门经理 .

    删除也可能是一团糟

    否则,您可以在部门和员工之间创建关联表以保存isManager属性 .

    或者将这最后放在员工表中(不是非常规范化但很好......)

    从一般观点来看,似乎不建议在关系模型中使用循环引用:In SQL, is it OK for two tables to refer to each other?

  • -1

    我认为,如果您将Employee中的部门列配置为允许null并正确设置级联,则可以解决问题 . 请不要使用同花顺

相关问题