2010-10-30 117 views
1

鉴于下面的例子(部门 - 项目):使用具有*嵌套*复合主键的@IdClass限制JPA 1.0?

甲系具有下列特性(复合主键):

@Entity 
@IdClass(DeptId.class) 
public class Department 
{ 
    @Id 
    @Column(name="number") 
    private Integer number; 

    @Id 
    @Column(name="country") 
    private String country; 

    @Column(name="name") 
    private String name; 

    @OneToMany(mappedBy="dept") 
    private Collection<Project> projects; 

    ... 
} 

这里的PK类:

public class DeptId implements Serializable 
{ 
    private Integer number; 
    private String country; 

    ... 
} 

之间的关系项目和部门是多对一的,这是一个设施可以有很多项目。 Project类本身使用引用Department组合键的组合键。重要提示:这只是关于@IdClass而不是@EmbeddedId的实现。

然后(有问题的)JPA 1.0 @IdClass实施将不得不寻找类似的东西(冗余deptNum和deptCtry属性): - 一个部门

@Entity 
@IdClass(ProjectId.class) 
public class Project 
{ 
    @Id 
    @Column(name="dept_number") 
    private Integer deptNumber; 

    @Id 
    @Column(name="dept_country") 
    private String deptCountry; 

    @Id 
    @Column(name="name") 
    private String name; 

    @ManyToOne 
    @JoinColumns({ 
     @JoinColumn(name="dept_number", referencedColumnName="number"), 
     @JoinColumn(name="dept_country", referencedColumnName="country") 
    })  
    private Department dept; 

    ... 
} 

的专案编号是内>这只是一个唯一的名称:

public class ProjectId implements Serializable 
{ 
    private String name; 
    private DeptId dept; 

    ... 
} 

这样做的问题是,无论是休眠还是EclipseLink的知道如何将两个冗余特性deptNum和deptCtry在项目映射到DEPTID的部门属性(或其中的性的判定)。 - > MappingException等

我的问题是:

这是JPA 1.0的限制,与复合键的表引用其它组合键使用@IdClass实现一般不会工作,因为JPA实现根本无法知道如何映射这些字段?

作为一种解决方法,您必须对这些类使用@EmbeddedId,或者使用JPA 2.0语法来使用@Id注释@XToX关联。我只是想确保我对此的看法是正确的。

感谢

回答

2

的问题张贴的代码是,JPA 1.0真的不允许复合主键类的嵌套。这个专案编号无效:

public class ProjectId implements Serializable 
{ 
    private String name; 
    private DeptId dept; 

    ... 
} 

DEPTID已被压扁,如:

public class ProjectId implements Serializable 
{ 
    private Integer deptNumber; 
    private String deptCountry; 
    private String name; 

    ... 
} 

我刚收到的EclipseLink版本去,但是Hibernate有与问题。我想知道如何告诉Hibernate假设JPA 1.0。

2

这样做的问题是,无论是休眠还是EclipseLink的知道如何在DEPTID

两个 冗余性能deptNum和deptCtry在项目映射到部门财产

这是为什么需要使用这种映射将ManyToOne外键定义为只读。这通过将JoinColumn属性insertableupdatable设置为false来完成。

所以请尝试以下操作:

@Entity 
@IdClass(ProjectId.class) 
public class Project 
{ 
    @Id 
    @Column(name="dept_number") 
    private Integer deptNumber; 

    @Id 
    @Column(name="dept_country") 
    private String deptCountry; 

    @Id 
    @Column(name="name") 
    private String name; 

    @ManyToOne 
    @JoinColumns({ 
     @JoinColumn(name="dept_number", referencedColumnName="number", insertable=false, updatable=false), 
     @JoinColumn(name="dept_country", referencedColumnName="country", insertable=false, updatable=false) 
    })  
    private Department dept; 
    ... 
} 
+0

这不关于可插入/可更新的东西。 ORM如何知道ProjectId的dept_x映射的属性?我没有与两个工作...休眠和EL。当EntityManagerFactory被实例化时,它们已经失败。这是有道理的... – Kawu 2010-10-31 12:02:15

+0

@Kawu:也许我没有听到你说的话,但当你重复上面的映射时,你必须使用JoinColumn中的可插入/可更新来使关联成为只读。如果它不起作用,则显示允许重现的映射和一些说明问题的痕迹。 – 2010-10-31 13:24:03

+0

让我澄清一下:JPA 1.0不允许在关联上使用@Id,这就是为什么在Project中有两个冗余成员deptNumber和deptCountry。由于这两个是Departments表中的PK,因此项目的组合键类ProjectId具有DeptId类型的成员。但Hibernate和EclipseLink都会抛出映射异常,因为它们不能将两个冗余的@Id成员deptNumber和deptCountry映射到DeptId的属性。我想知道这是一个普遍的限制,还是有办法告诉JPA 1.0 ORM如何映射它们。 (JPA 1.0要求字段的名称匹配) – Kawu 2010-11-01 11:03:06

3

是的,这是JPA 1.0的限制,在JPA 2.0中进行了更正。在新的JPA 2.0中,您可以将ID注释放在您的部门关系上,并完全避免使用重叠的deptCountry和deptNumber属性,并且键类使用嵌套。在JPA 1.0中,只有基本映射可以标记为ID的一部分,需要重新映射映射和一些代码以确保值/关系在持久存储时正确放入缓存。由于冗余,正如其他答案中所述,字段映射之一需要通过insertable/updatable = false标记为只读。这样做虽然意味着值不会合并到缓存中 - 所以更改(例如插入时,因为一旦存在就不能更改对象ID)将不会被反映,除非对象从数据库刷新。如果您将JoinColumns标记为只读,则需要从引用的部门获取值,并在您想要保留项目时手动将它们放入相应的基本ID属性中。但是,您也可以将基本属性标记为只读。 Eclipselink无论如何不会有任何问题,并将使用关联的部门实体正确设置字段值(只要它在项目上调用persist之前设置)。不过请注意,当您在不同的上下文中回读项目时,可能会或可能不会填充基本属性 - 这取决于实体是否从数据库中刷新。如果它们是只读的,则它们不会合并到共享缓存中,因为它们只能读取,不应该更改。因此,他们可以被忽略,或者如果他们必须填充,实体刷新或在事件中从部门设置的值。

通过使用JPA2.0 @MapsId,可以重复使用相同的模型,该模型还将使用来自关系的值为您保留基本映射。只有我看到的是,你不需要访问关系(可能导致不必要的连接或懒惰关系上的数据库访问)来获取外键/ ID字段值。

至于ZipArea EclipseLink异常,它们是由于ZipAreaId具有ZipId zip属性而不是它被展平。 JPA 1.0要求密钥类具有与实体中每个@ID属性相同类型和名称的属性。