Difference between revisions of "EclipseLink/Development/JPA 2.0/mappedbyid"

From Eclipsepedia

Jump to: navigation, search
(Test)
(Internal processing)
Line 130: Line 130:
  
 
==== Internal processing ====
 
==== Internal processing ====
 +
When processing the @ManyToOne mapping, the mapping for sargeantPK will be retrieved from the embeddable descriptor for MasterCorporalId and the following keys added:
 +
 +
<code><pre>
 +
DatabaseField dependentField = sargeantPKMapping.getField(); // The mapping from the embeddable class
 +
DatabaseField parentField = getReferenceDescriptor().getPrimaryKeyField(); // The primary key mapping from the Sargeant entity
 +
manyToOneMapping.addForeignKeyField(dependentField, parentField);
 +
 +
// The example above will yield.
 +
// manyToOneMapping.addForeignKeyField("SARGEANTPK", "ID");
 +
 +
// And to ensure the primary key class is properly initialized from the CMP3Policy
 +
 +
mapping.setIsDerivedIdMapping(true);
 +
mapping.setMappedByIdValue(mappedByIdValue);
 +
 +
</pre></code>
  
 
==Work Required==
 
==Work Required==

Revision as of 11:25, 24 April 2009

Contents

MappedById Support

JPA 2.0 Root | Enhancement Request

Issue Summary

In JPA 1.0 primary key columns could only be mapped to @Basic attributes. Primary Keys that were derived from Foreign Keys had to be mapped twice, once as the relationship mapping and again as an @Basic. JPA 2.0 adds the functionality to designate a Relationship as providing the primary key for an Entity, see | DerivedId . When using an embeddedid, a @MappedById annotation can be used on a relationship mapping to indicate that it uses the same Id field that is also defined by the target ID field in the Embeddedid.

See JPA 2.0 section 2.4.1 for details.

General Solution

The EmbeddedID will be difficult to support as values in the EmbeddedID will need to be populated by EclipseLink on persist(), merge() calls even though they are not the sources of Identity for the Entity. Even more complicated if the derived ID is an IdClass then an instance of that class must be stored in the EmbeddedId which will be new functionality in EclipseLink. Transformation Mapping may be leveraged in combination with the CMP3Policy to support this functionality.

Metadata processing

The metadata processing will need a number of changes to support the notion of id classes and embedded id classes within their own embedded id's. The spec provided 6 examples, so we'll work through each and discuss the metadata processing behevior and any changes needed to it.

Example 1

The parent entity has a simple primary key and the dependent entity uses EmbeddedId to represent a composite key.

Model

@Entity
@Table(name="JPA_SARGEANT")
public class Sargeant {
    @Id
    @Column(name="ID")
    @GeneratedValue(strategy=TABLE, generator="SARGEANT_TABLE_GENERATOR")
    @TableGenerator(
        name="SARGEANT_TABLE_GENERATOR", 
        table="JPA_SARGEANT_SEQ", 
        pkColumnName="SEQ_NAME", 
        valueColumnName="SEQ_COUNT",
        pkColumnValue="SARGEANT_SEQ",
        initialValue=50
    )
    long sargeantId;

    @Basic
    @Column(name="NAME")
    String name;
    
    public String getName() {
        return name;
    }
    
    public long getSargeantId() {
        return sargeantId;
    }

    public void setName(String name) {
        this.name = name;
    }
    
    public void setSargeantId(long sargeantId) {
        this.sargeantId = sargeantId;
    }
}

@Entity
@Table(name="JPA_MASTER_CORPORAL")
public class MasterCorporal {
    @EmbeddedId 
    MasterCorporalId id;
    
    @ManyToOne 
    @MappedById("sargeantPK")
    Sargeant sargeant;
    
    public MasterCorporalId getId() {
        return id;
    }
    
    public Sargeant getSargeant() {
        return sargeant;
    }
    
    public void setId(MasterCorporalId id) {
        this.id = id;
    }

    public void setSargeant(Sargeant sargeant) {
        this.sargeant = sargeant;
        id.setSargeantPK(sargeant.getSargeantId());
    }
}

@Embeddable
public class MasterCorporalId {
    @Column(name="NAME")
    String name;
    
    @Column(name="SARGEANTPK")
    long sargeantPK;
    
    public String getName() {
        return name;
    }
    
    public long getSargeantPK() {
        return sargeantPK;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public void setSargeantPK(long sargeantPK) {
        this.sargeantPK = sargeantPK;
    }
}

Test

EntityManager em = createEntityManager();
beginTransaction(em);
        
Sargeant sargeant = new Sargeant();
MasterCorporal masterCorporal = new MasterCorporal();
MasterCorporalId masterCorporalId = new MasterCorporalId();
sargeant.setName("Sarge");
em.persist(sargeant);
            
masterCorporalId.setName("Corpie");
masterCorporal.setId(masterCorporalId);
masterCorporal.setSargeant(sargeant);
em.persist(masterCorporal);
            
commitTransaction(em);         
closeEntityManager(em);

Internal processing

When processing the @ManyToOne mapping, the mapping for sargeantPK will be retrieved from the embeddable descriptor for MasterCorporalId and the following keys added:

DatabaseField dependentField = sargeantPKMapping.getField(); // The mapping from the embeddable class
DatabaseField parentField = getReferenceDescriptor().getPrimaryKeyField(); // The primary key mapping from the Sargeant entity
manyToOneMapping.addForeignKeyField(dependentField, parentField);

// The example above will yield.
// manyToOneMapping.addForeignKeyField("SARGEANTPK", "ID");

// And to ensure the primary key class is properly initialized from the CMP3Policy

mapping.setIsDerivedIdMapping(true);
mapping.setMappedByIdValue(mappedByIdValue);

Work Required

  1. Develop model for testing access type settings
    approx ? days
  2. Update Processing
    approx ? days