Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

EclipseLink/Development/JPA2.0/association-override-join-table

Association Override Join Table support

JPA 2.0 Root | Enhancement Request

Issue Summary

JPA 2.0 specification introduced support for relational mappings such as 1-M, M-M etc on embeddable class. With that comes the option to specify an association override to apply to those mappings within the embeddable, namely those mappings that use a join table. Note an association override can also be specified at the entity level and applied to a mapping from a mapper superclass. This is existing functionality, however with the introduction of the join table element within the association override in JPA 2.0, this support needs to be implemented.

At the same time, changes will be made to support association override join columns on a uni-directional one to many from an embeddable class. Note, that support (although not explicitely supported from the spec in JPA 1.0) for association override join columns to 1-1 and 1-M mappings from an embeddable class was already implemented and tested.

Association overrides are described in detail in section 11.1.2 of the specification.

General Solution

For the most part, the solution for this will mainly be in the metadata processing. However, to support an association override join table from an embeddable class will require some changes to core code, namely to AggregateObjectMapping.

Examples

Annotation

@Embeddable
public class Accredidation {

    @OneToMany(cascade={PERSIST, MERGE})
    @JoinColumn(name="IGNORED_JOIN_COLUMN")
    List<Official> officials;
    
    @ManyToMany(cascade={PERSIST, MERGE})
    @JoinTable(name="IGNORED_JOIN_TABLE")
    List<Witness> witnesses;

    ...
}

@MappedSuperclass
public class RatedBeerConsumer {

    @ManyToMany(cascade=ALL)
    // Expert beer consumer will use the join table as is here, whereas, novice
    // beer consumer will provide an association override.
    @JoinTable(
        name="JPA_CONSUMER_COMMITTEE",
        joinColumns=@JoinColumn(name="CONSUMER_ID", referencedColumnName="ID"),
        inverseJoinColumns=@JoinColumn(name="COMMITTEE_ID", referencedColumnName="ID")
    )
    private List<Committee> committees;

    @Embedded
    // Expert beer consumer will use these overrides, whereas, novice beer 
    // consumer will override them by defining class level overrides.
    @AssociationOverrides({
        @AssociationOverride(name="witnesses", joinTable=@JoinTable(name="EBC_ACCREDIDATION_WITNESS",
            joinColumns=@JoinColumn(name="EBC_ID", referencedColumnName="ID"),
            inverseJoinColumns=@JoinColumn(name="WITNESS_ID", referencedColumnName="ID"))),
        @AssociationOverride(name="officials", joinColumns=@JoinColumn(name="FK_EBC_ID"))
    })
    private Accredidation accredidation;

    ...
}

@Entity
@AssociationOverrides({
    @AssociationOverride(name="committees", joinTable=@JoinTable(name="JPA_NBC_COMMITTEE",
        joinColumns=@JoinColumn(name="NBC_ID", referencedColumnName="ID"),
        inverseJoinColumns=@JoinColumn(name="COM_ID", referencedColumnName="ID"))),
    @AssociationOverride(name="accredidation.officials", joinColumns=@JoinColumn(name="FK_NBC_ID")),
    @AssociationOverride(name="accredidation.witnesses", joinTable=@JoinTable(name="NBC_ACCREDITATION_WITNESS",
        joinColumns=@JoinColumn(name="NBC_ID", referencedColumnName="ID"),
        inverseJoinColumns=@JoinColumn(name="WITNESSID", referencedColumnName="ID")))
})
public class NoviceBeerConsumer extends RatedBeerConsumer {
   ...
}

@Entity
// No association overrides, will use those defined on the mappings from the mapped superclass.
public class ExpertBeerConsumer extends RatedBeerConsumer {
   ...
}

XML

<embeddable class="Accredidation">
  <attributes>
    <one-to-many name="officials">
      <join-column name="IGNORED_JOIN_COLUMN"/>
        <cascade>
          <cascade-persist/>
          <cascade-merge/>
        </cascade>
      </one-to-many>
    <many-to-many name="witnesses">
      <join-table name="IGNORED_JOIN_TABLE"/>
        <cascade>
          <cascade-persist/>
          <cascade-merge/>
        </cascade>
    </many-to-many>
    
    ...

  </attributes>
  
  ...

</embeddable>

<mapped-superclass class="RatedBeerConsumer" access="FIELD">
  <attributes>

    <many-to-many name="committees">
      <!--  
        Expert beer consumer will use the join table as is here, whereas, novice
        beer consumer will provide an association override.    
      -->
      <join-table name="XML_EBC_COMMITTEE">
        <join-column name="XML_EBC_ID" referenced-column-name="ID"/>
        <inverse-join-column name="XML_COMMITTEE_ID" referenced-column-name="ID"/>
      </join-table>
      <cascade>
        <cascade-all/>
      </cascade>
    </many-to-many>

    <embedded name="accredidation">
      <!--
        Expert beer consumer will use these overrides, whereas, novice beer 
        consumer will override them by defining class level overrides. 
      -->
      <association-override name="witnesses">
        <join-table name="XML_EBC_ACCREDIDATION_WITNESS">
          <join-column name="XML_EBC_ID" referenced-column-name="ID"/>
            <inverse-join-column name="XML_WITNESS_ID" referenced-column-name="ID"/>
        </join-table>
      </association-override>
      <association-override name="officials">
        <join-column name="FK_EBC_ID"/>
      </association-override>
    </embedded>

    ...

  </attributes>

  ...

</mapped-superclass>

<entity name="XML_NBC" class="NoviceBeerConsumer" access="PROPERTY">
  <association-override name="committees">
    <join-table name="XML_NBC_COMMITTEE">
      <join-column name="XML_NBC_ID" referenced-column-name="ID"/>
      <inverse-join-column name="XML_COM_ID" referenced-column-name="ID"/>
    </join-table>
  </association-override>
  <association-override name="accredidation.officials">
    <join-column name="FK_NBC_ID"/>
  </association-override>
  <association-override name="accredidation.witnesses">
    <join-table name="XML_NBC_ACCREDITATION_WITNESS">
      <join-column name="XML_NBC_ID" referenced-column-name="ID"/>
        <inverse-join-column name="XML_WITNESSID" referenced-column-name="ID"/>
      </join-table>
  </association-override>

  ...

</entity>

<entity name="XML_EBC" class="ExpertBeerConsumer" access="PROPERTY">

  <!-- No association overrides, will use those defined on the mappings from the mapped superclass. -->

  ...

</entity>

Work Required

  1. Develop model for testing
    approx 5 day
  2. Update Processing
    approx 10 days

Back to the top