5

Does someone know if it is possible to establish a backreference from within a JPA @EmbeddedId.

So for example there is an Entity of the Form

@Entity
public class Entity1 {
    @Id
    @GeneratedValue
    private String identifier;

    private Entity1 relationToEntity1;
    //Left out the getters and setters for simplicity
}

And a second entity with a complex embedded Id. One part of this second entity is a reference to its parent entity. Like so:

@Entity
public class Entity2 {
    @EmbeddedId private Entity2Identifier id;
    //Left out the getters and setters for simplicity.
}

@Embedabble
public class Entity2Identifier {
    private String firstPartOfIdentifier;
    private Entity1 parent;
    //Left out the getters and setters for simplicity.
}

When I try to save such a construct via JPA (Implementation is EclipseLink) to a database I get several exceptions of the form:

Exception [EclipseLink-93] (Eclipse Persistence Services - 1.1.0.r3639-SNAPSHOT): 
org.eclipse.persistence.exceptions.DescriptorException
Exception Description: The table [ENTITY1] is not present in this descriptor.
Descriptor: RelationalDescriptor(test.Entity2 --> [DatabaseTable(ENTITY2)])

Did someone encounter such a problem and has a solution?

ali
  • 1,475
  • 4
  • 22
  • 40

2 Answers2

4

What you are looking for is a derived Id. If you are using JPA 2.0 then the following will work. You really do not want the whole Parent to be part of the PK, just the parent's PK.

@Entity
public class Entity1 {
    @EmbeddedId
    private ParentId identifier;

    @OneToOne(mappedBy="relationToEntity1")
    private Entity2 relationToEntity2;

    //Left out the getters and setters for simplicity
}

@Entity
public class Entity2 {
    @EmbeddedId private Entity2Identifier id;
    //Left out the getters and setters for simplicity.

    @MapsId("parentId")
    @OneToOne
    private Entity1 parent;

}

@Embedabble
public class Entity2Identifier {
    private String firstPartOfIdentifier;
    private ParentId parentId;
    //Left out the getters and setters for simplicity.
}
David V
  • 11,531
  • 5
  • 42
  • 66
Gordon Yorke
  • 1,996
  • 11
  • 7
1

The @EmbeddedId annotation does not allow relationships in the composite identity class. From the EmbeddedId JavaDoc:

Relationship mappings defined within an embedded id class are not supported.

I understand that you want Entity2Identifier to contain the key to the parent, but in your example, you're creating a relationship to the entire object rather than just including the primary key of the parent. Even if this construction worked, you would be establishing the composite key to be not only the primary key of the parent, but the entire state of the parent.

If you're simply looking for an easy way to establish bi-directional relationships, you can do so with the the @OneToOne annotation and the mappedBy attribute:

@Entity
public class Entity1 {
    @Id
    @GeneratedValue
    private String identifier;

    @OneToOne(mappedBy="relationToEntity1")
    private Entity2 relationToEntity2;
    ...
}

@Entity
public class Entity2 {

    @OneToOne
    private Entity1 relationToEntity1;
    ...
}

With this set of annotations, the JPA provider will handle Entity1.relationToEntity2 and Entity2.relationToEntity1 properly as a bi-directional relationship. You might also wish to override the default cascade behavior (none) as well as the default orphan removal behavior (none). See the JavaDoc for more details.

Kim Burgaard
  • 3,508
  • 18
  • 11
  • Thanks for your answer. Actually I know that one. The problem is that my primary key consists of multiple parts, one of which is the parent entity. This means there is some value defining the entity but it is only valid in the context of the parent. – ali Jan 10 '11 at 05:43