java - 一旦外键是主键的一部分,如何使用复合键映射自连接

标签 java hibernate composite-key self-join

我遇到了以下问题:我必须将我的 Employee 类映射到以下数据库模式(其中 id1 和 id2 是复合主键):

--------------------------
| id1 | id2 | ManagerId2 |
--------------------------
| 1   | 1   | NULL       | <--- Have no manager / Can be manager of many   
--------------------------
| 1   | 2   | 1          | <--- Is manager / Has manager 1-1 
--------------------------
| 1   | 3   | 1          | <--- Is manager / Has manager 1-1 
--------------------------

我知道外键必须具有与其引用的主键相同的列(相同数量的列)。关键是一旦 Employeeid1 = 1 插入,它必须只引用 id1 = 1 的经理。一种保持完整性并避免出现以下情况的方法:

---------------------------------------
| id1 | id2 | ManagerId1 | ManagerId2 |
---------------------------------------
| 1   | 1   | NULL       | NULL       | <--- Have no manager / Can be manager of many   
---------------------------------------
| 2   | 1   | NULL       | NULL       | <--- Have no manager / Can be manager of many   
---------------------------------------
| 1   | 2   | 2          | 1          | <--- THIS IS NOT ALLOWED
---------------------------------------
| 1   | 3   | 2          | 1          | <--- NOR THIS
---------------------------------------

到目前为止,我得到的最好的是以下映射(尽管它按预期创建了表,但它只是不填充 ManagerId2 字段):

@Entity
@Table(name="Employee")
public class Employee {

    public Employee(){
    }

    @EmbeddedId
    private EmployeeId id;
    public void setId(EmployeeId id) {
        this.id = id;
    }
    public EmployeeId getId() {
        return id;
    }

    @ManyToOne(cascade={CascadeType.ALL})
    @JoinColumns({ 
        @JoinColumn(name = "id1", referencedColumnName = "id1", insertable=false, updatable=false), //its fine to have this attribute not insertable nor updatable
        @JoinColumn(name = "id2_manager", referencedColumnName = "id2", insertable=false, updatable=false) //but I must be able to update this one!
    })
    private Employee manager;
    public Employee getManager() {
        return manager;
    }
        public void setManager(Employee manager) {
        this.manager = manager;
    }
}

@Embeddable
public class EmployeeId implements Serializable{

    public EmployeeId() {

    }

    public EmployeeId(int id1, int id2) {
        this.id1 = id1;
        this.id2 = id2;
    }

    private int id1;

    private int id2;

    public int getId1() {
        return id;
    }

    public void setId(int id1) {
        this.id1 = id1;
    }

    public int getId2() {
        return id2;
    }

    public void setId2(int id2) {
        this.id2 = id2;
    }

            //hashCode and equals properly overriden
}

看了一整天,我似乎什么也找不到! 有人可以告诉我我做错了什么,或者指出任何好的资源吗?

PS.: 我无法更改数据库架构,这不是一个选项

最佳答案

我不确定如何使用注释来做到这一点,但我找到了一个可能对您有所帮助的解决方法。

@Entity
@Table(name = "Employee")
public class Employee {

    @EmbeddedId
    private EmployeeId id;

    private Integer id2_manager;

    @PrePersist
    @PreUpdate
    public void prePersistUpdate() {
        if (manager != null)
            id2_manager = manager.getId().getId2();
    }

    public Employee() {
    }

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

    public EmployeeId getId() {
        return id;
    }

    @ManyToOne(cascade = { CascadeType.ALL })
    @JoinColumns({ @JoinColumn(name = "id1", referencedColumnName = "id1", insertable = false, updatable = false),
            @JoinColumn(name = "id2_manager", referencedColumnName = "id2", insertable = false, updatable = false, nullable = true) })
    private Employee manager;

    public Employee getManager() {
        return manager;
    }

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

测试

    static EntityManagerFactory emf;
    static EntityManager em;

    public static void main(String[] args) {

        emf = Persistence.createEntityManagerFactory("unit");
        em = emf.createEntityManager();

        Employee manager = new Employee();
        manager.setId(new EmployeeId(1, 1));

        Employee e1 = new Employee();
        e1.setId(new EmployeeId(1,2));
        e1.setManager(manager);


        em.getTransaction().begin();

        em.persist(manager);
        em.persist(e1);

        em.getTransaction().commit();

        Employee e2 = em.find(Employee.class, new EmployeeId(1, 2));

        System.out.println(e2.getManager().getId().getId1() + "-" + e2.getManager().getId().getId2());
        //  prints  1-1

    }

关于java - 一旦外键是主键的一部分,如何使用复合键映射自连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15145110/

相关文章:

java - Postgresql JPA Hibernate 创建数据库

java - 将 Vaadin CheckBox 保存到 JPA 的正确方法是什么?

java - hibernate中复合键的Where子句

java - 我将引用作为输出。我应该在程序中包含什么才能获得输出

java - 类型转换中的模棱两可的行为

java - 当实体具有多对多关系时如何使用条件查询?

java - Hibernate 检索父/子

python - web2py 中的复合键

mysql - 如何在 MySQL 中使用前缀索引进行仅索引扫描

java - 从 PDImageXObject 获取图像大小