views:

56

answers:

3

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

+1  A: 

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;
    ...
}
Pascal Thivent
It's not about the insertable/updatable stuff. How do the ORMs know which properties of ProjectId's dept_x map to? I doesn't work with both... Hibernate AND EL. They already fail when the EntityManagerFactory is instantiated. It makes sense sort of...
Kawu
@Kawu: Maybe I'm not getting what you're saying but when you repeat mappings like above, you have to make the association read-only using insertable/updatable in the `JoinColumn`. If it doesn't work, show a mapping allowing to reproduce and some traces illustrating the problem.
Pascal Thivent