使用@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 projects; ... } 

这里的PK类:

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

项目和部门之间的关系是多对一的,那就是一个可以有很多项目的deptartment。 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; ... } 

ProjectId是:

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

这个问题是Hibernate和EclipseLink都不知道如何将Project中的两个冗余属性deptNum和deptCtry映射到DeptId中的dept属性(或其中的属性)。 – > MappingException等

我的问题是:

这是JPA 1.0的限制,使用带有@IdClass实现的其他复合键的复合键的表通常不起作用 ,因为JPA实现根本无法知道如何映射这些字段?

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

谢谢

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

通过使用JPA2.0 @MapsId可以重用相同的模型,它也将使用关系中的值来维护基本映射。 我看到的唯一好处是你不需要访问关系(可能导致不必要的连接或对惰性关系的数据库访问)来获取外键/ id字段值。

至于ZipArea EclipseLinkexception,它们归因于ZipAreaId具有ZipId zip属性而不是被展平。 JPA 1.0要求密钥类为实体中的每个@ID属性提供相同类型和名称的属性。

这个问题是Hibernate和EclipseLink都不知道如何将Project中的两个冗余属性deptNum和deptCtry映射到DeptId中的dept属性

这就是您需要使用这种映射将ManyToOne外键定义为只读的原因 。 这可以通过将JoinColumn属性设置为updatable insertableupdatablefalse

请尝试以下方法:

 @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; ... } 

发布代码的问题是,JPA 1.0实际上不允许嵌套复合主键类。 此ProjectId无效:

 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。