JPA 1.0 使用 @IdClass 和*嵌套*复合主键的限制?

发布于 2024-09-30 09:36:47 字数 1786 浏览 4 评论 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;

    ...
}

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 语法来用 @Id 注释 @XToX 关联。我只是想确保我对此的看法是正确的。

谢谢

Given the following example (departments - projects):

A department has the following properties (composite primary key):

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

    ...
}

Here the PK class:

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

    ...
}

The relationship between projects and departments is many-to-one, that is a deptartment can have many projects. The Project class is itself using a composite key referencing Department's composite key. Important note: it's only about the implementation with @IdClass not @EmbeddedId.

Then the (problematic) JPA 1.0 @IdClass implementation would have to look something like that (redundant deptNum and deptCtry properties): -> it's just a unique name within a department

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

    ...
}

The ProjectId is:

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

    ...
}

The problem with this is that neither Hibernate nor EclipseLink know how to map the two redundant properties deptNum and deptCtry in Project to the dept property in DeptId (or the properies within it). -> MappingException etc.

My question is:

Is this a limitation of JPA 1.0, that tables with composite keys referencing other composite keys with @IdClass implementations generally WON'T work, because the JPA implementation simply can't know how to map these fields?

As a workaround, you'd have to use @EmbeddedId for these classes or use JPA 2.0 syntax to annotate the @XToX associations with @Id. I just want to make sure my view on this is right.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

能怎样 2024-10-07 09:36:47

是的,这是 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 属性具有相同类型和名称的属性。

Yes, this is a limitation of JPA 1.0, corrected in JPA 2.0. In the new JPA 2.0, you can put the ID annotation on your dept relationship and completely avoid having the redundent deptCountry and deptNumber attributes, with the key class using nesting. In JPA 1.0, only basic mappings can be marked as apart of the ID, requiring redundent mappings and some code to ensure that the values/relationships get put into the cache correctly when persisting. Because of the redundancy, as mentioned in other answers, one of the mappings for a field needs to be marked read-only via the insertable/updatable=false. Doing so though means that value is not merged into the cache - so changes (such as on insert, since you can't change an objects ID once it exists) will not be reflected unless the object is refreshed from the database. If you mark the JoinColumns as read-only, you will need to get the values from the referenced dept and put them into the correspoinding basic id attributes manually when you want to persist a Project. But, you can also mark the basic attributes as read-only. Eclipselink anyway will not have any problems and will correctly set the field values using the associated dept entity (as long as it is set before persist is called on the Project). Notice though that the basic attributes may or may not be populated when you read back the project in a different context- this will depend on if the entity is refreshed from the database or not. If they are read-only, they do not get merged into the shared cache since they, being read only, should not have changed. So they can be just ignored, or if they must be populated, the entity refreshed or the values set from the dept in an event.

This same model can be reused by using the JPA2.0 @MapsId, which will also maintain the basic mappings using the values from the relationship for you. Only benifit I see is that you don't need to access the relationship (potentially causing unneccessary joins or database access on lazy relationships) to get the foreign key/id field values.

As for the ZipArea EclipseLink exceptions, they are due to ZipAreaId having a ZipId zip attribute instead it being flattened out. JPA 1.0 requires the key class to have an attribute of the same type and name for each @ID attribute in the Entity.

伪装你 2024-10-07 09:36:47

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

这就是为什么您需要定义 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;
    ...
}

The problem with this is that neither Hibernate nor EclipseLink know how to map the two redundant properties deptNum and deptCtry in Project to the dept property in DeptId

This is why you need to define the ManyToOne foreign key(s) as read-only with this kind of mapping. This is done by setting the JoinColumn attributes insertable and updatable to false.

So try the following:

@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;
    ...
}
秉烛思 2024-10-07 09:36:47

发布的代码的问题是,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 被假定。

The problem with the posted code is, that JPA 1.0 really doesn't allow nesting of composite primary key classes. This ProjectId is invalid:

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

    ...
}

DeptId has to be flattened, like:

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

    ...
}

I just got an EclipseLink version to go, but Hibernate has problems with that. I wonder how to tell Hibernate that JPA 1.0 is assumed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文