如何在Hibernate中正确实现具有复合id的域对象?

时间:2010-09-11 01:35:11

标签: java hibernate orm jpa

我有以下域对象:

public class Department  {
     private long departmentId;
}
public class Manager {
     private long managerId;
}    
public class Project  {
     private ProjectId compositeId;
     @ManyToOne
     private Department department;
     @ManyToOne
     private Manager manager;
}
public class ProjectId  {
     private long departmentId;
     private long managerId;
}

项目由复合键(departmentId,managerId)标识。问题是如何实现Project.setManager(..)或Project.setDepartment(..)?下面列出的实施是最佳做法吗?

public void setManager( Manager manager ) {
     this.manager = manager;
     this.compositeId.setManagerId( manager.getId() );
}

我的理解是每当设置属性时都需要更新compositeId。

更难和相关的问题是应该如何实现Project.setCompositeId(..)?项目将无法根据复合ID(长)更新物业经理或部门。在不更新属性的情况下覆盖compositeId会使Project处于不协调状态。

1 个答案:

答案 0 :(得分:2)

我建议如下:

@Entity
@IdClass(ProjectId.class)
public class Project  {
     @Id @Column(name="DEPARTMENT_ID")
     private long departmentId;
     @Id @Column(name="MANAGER_ID")
     private long managerId;

     @ManyToOne
     @PrimaryKeyJoinColumn(name="DEPARTMENT_ID", referencedColumnName="DPT_ID")
     private Department department;
     @ManyToOne
     @PrimaryKeyJoinColumn(name="MANAGER_ID", referencedColumnName="MGR_ID")
     private Manager manager;

     ...
}

JPA Wikibook

中详细说明了这种映射
  

JPA 1.0要求所有@Id映射   是基本映射,所以如果你的ID来了   从一个外键列到一个   你是OneToOneManyToOne映射   还必须定义Basic @Id映射   对于外键列。原因   因为这部分是Id必须的   是一个简单的身份和对象   缓存目的,并用于   IdClassEntityManager find()   API。

     

因为您现在有两个映射   你必须使用相同的外键列   定义将写入哪一个   数据库(必须是基础   一),所以OneToOneManyToOne   必须定义外键   只读。这是通过完成的   设置JoinColumn属性   insertableupdatable为false,或   使用@PrimaryKeyJoinColumn   而不是@JoinColumn

     

具有两个映射的副作用   对于同一列,就是你现在   必须保持两者同步。这是   通常通过设置完成   OneToOne属性的方法也是   将Basic属性值设置为   目标对象的id。这可以成为   如果目标非常复杂   对象的主键是a   GeneratedValue,在这种情况下你必须   确保目标对象的id具有   在关联两个对象之前已分配

     

(...)

     

示例ManyToOne id注释

...
@Entity
@IdClass(PhonePK.class)
public class Phone {
    @Id
    @Column(name="OWNER_ID")
    private long ownerId;

    @Id
    private String type;

    @ManyToOne
    @PrimaryKeyJoinColumn(name="OWNER_ID", referencedColumnName="EMP_ID")
    private Employee owner;
    ...

    public void setOwner(Employee owner) {
        this.owner = owner;
        this.ownerId = owner.getId();
    }
    ...
}

参考