Question

Is it possible to exist Bidirectional Relationship between Embeddables and Entities or only Unidirectional relationship exist ?

@Entity
public class Employee {
  @Id
  private long id;
  ...
  @Embedded
  private EmploymentPeriod period;
  ...
}
@Embeddable 
public class EmploymentPeriod {
  @Column(name="START_DATE")
  private java.sql.Date startDate;

  @Column(name="END_DATE")
  private java.sql.Date endDate;

  @OneToMany
  private EntityABCD entityABCD ;
  ....
}
@Entity
public class EntityABCD {
  @Id
  private long id;
  ...
  @ManyToOne(mappedby="entityABCD")
  private EmploymentPeriod period;
  ...
}

According to JPA Specification : 2.5 Embeddable Classes

 An entity cannot have a unidirectional relationship to the embeddable class of another entity (or itself).

Please clarify above line as specified by JPA specification .

Was it helpful?

Solution

When each entity points to the other, the relationship is bidirectional.
If only one entity points to the other, the relationship is unidirectional.

In your particular case, the sentence:

An entity cannot have a unidirectional relationship to the embeddable class of another entity (or itself)

can be translated to:

EntityABCD entity cannot have a unidirectional relationship to the embeddable class EmploymentPeriod of another Employee entity.

so in other words:

If Employee entity has an embedded EmploymentPeriod, it is not possible to define an unidirectional relationship from EntityABCD entity to embeddable EmploymentPeriod of entity Employee.

Why?

Because an embeddable object has no identity of its own (lack of primary key) it needs to be treated only as a part of the entity that encapsulates it. From a database point of view, an embedded object is stored with the rest of the entity attributes in a single row.

As a consequence of the above, if someone would try to create an unidirectional relationship from EntityABCD the EmploymentPeriod it is simply not possible due to lack of identity of the EmploymentPeriod, thus it is not possible to create the foreign key in the embedded object.

How to overcome the problem with the foreign key?

Foreign key needs to be physically created outside embeddedable class and it depends on type of relationship. An example (:

@Entity
public class Employee {
  @Id
  private long id;

  @Embedded
  private EmploymentPeriod period;
}

@Embeddable
public class EmploymentPeriod {
    @ManyToOne //owning relationship
    @JoinColumn //FK in EMPLOYEE table (by default: ENTITYABCD_ID) 
    private EntityABCD entityABCD;

    @ManyToMany //owning relationship
    @MapKey(name="id") //refers to EntityABCD.id
    @JoinTable //FK in the join table (by default: EMPLOYEE_ENTITYABCD)
    private Map<Long, EntityABCD> entitiesABCD;
}

@Entity
public class EntityABCD {
    @Id
    private long id;

    @OneToMany(mappedBy = "period.entityABCD") //non-owning relationship
    List<Employee> employee;

    @ManyToMany(mappedBy="period.entitiesABCD") //non-owning relationship
    private List<Employee> employees;
}

When bidirectional relationships exist within an embedded object, they are treated as though they exist in the owning entity (Employee) and the target entity (EntityABCD) points back to the owning entity, not to the embedded object (EmploymentPeriod).

It is worth to mention that embeddables can only embed:

  • other embeddables
  • relationships to entities
  • element collections of basic / embeddable type

OTHER TIPS

This is really complex to explain but i will give it a shot. This is what the spec says

An embeddable class may contain a relationship to an entity or collection of entities. Since instances of embeddable classes themselves have no persistent identity, the relationship from the referenced entity is to the entity that contains the embeddable instance(s) and not to the embeddable itself.[17] An embeddable class that is used as an embedded id or as a map key must not contain such a relationship.

[17] An entity cannot have a unidirectional relationship to the embeddable class of another entity (or itself).

The scenario is...

Entity1 has a property of an Embeddable and that Embeddable too has a property pointing to entity2 within itself.

Note that this is a complex embedded object because it is "shared" between two entities. Even though the spec says embeddables should not be shared, it can be it just has undefined semantics.

The part of what the spec is talking about is what happens within the Embeddable, in this case you have the embeddable with a reference within it pointing to an Entity. If you think about it there needs to be a bi-directional relationship cause an embeddable has no primary key so it needs some sort of way to point to the the entity that it is referring to (Foriegn key) eg @OneToOne and since the embeddable can never be the owner it cant create the foriegn key , the entity that the embeddable is referencing (Entity2) has to allocate the foreign key to it and the only way to do that is to have a reference within its self marked as @embedded, and hence you have a bi-directional relationship.

Below is some code

@Entity
public class Entity1 {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Embedded
    private Embeddable embeddable;

     //getter/setter
}

@Embeddable
public class Embeddable {

    @OneToOne
    private Entity2 entity2;

    public Entity2 getEntity2() {
        return entity2;
    }

    public void setEntity2(Entity2 entity2) {
        this.entity2 = entity2;
    }
}

@Entity
public class Entity2 {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Embedded
    private Embeddable embeddable;

     //getter/setter
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top