EclipseLink/Development/JPA2.0/Extended Map support/MappedKeyMapContainerPolicy

From Eclipsepedia

Jump to: navigation, search

The JPA 2.0 specification allows maps to be specified in several new ways. At the base, the functionality comes down to two possibilities:

  1. The map key is stored somewhere in the target object (i.e. it is a mapped value in the target object)
  2. The map key is not stored in the target object (i.e. it can be composed from data stored in tables, but not in the target object)

A MappedKeyMapContainerPolicy will be used for the second case, the case where the map key is stored in the database, but not specifically mapped in the target object.

Feedback

Contents

Goals

  • Provide a way of satisfying the JPA 2.0 specification requirements of allowing map keys to be stored outside of the target object's mapping.
  • Support basic EclipseLink CRUD and additional features like batch reading,join fetch, fetch groups,
  • As a second step, implement the JPA 2.0 metadata including Annotations and XML configuration
  • Implement core-level testing for the basic feature
  • Implement jpa-level testing for JPA 2.0 parts of the functionality

High Level Design

MapComponentMapping/MapKeyMapping

Two new interfaces will be created:

  1. MapComponentMapping
  2. MapKeyMapping extends MapComponentMapping

MapComponentMapping

Provides facilities that allow an instance of an object to be built from a database row and will be implemented by all mappings that be represented as a Map

  • DirectCollectionMapping
  • AggregateCollectionMapping
  • OneToManyMapping
  • UnidirectionalOneToManyMapping
  • ManyToManyMapping

MapKeyMapping

This subinterface of MapComponentMapping contains the majority of the functionality necessary to build map keys:

  • Adding required fields to selectionQuery, insertQuery, deleteQuery for the owning mapping
  • Extracting results of queries and using them to build the target
  • Cloning the target
  • Initiailization
  • Attribute Accessors for these mappings will not be used

It will be implemented by all mappings that could represent a map key

  • AbstractDirectMapping
  • AggregateObjectMapping
  • OneToOneMapping

Only MapKeyMappings will be eligible as the key for a map using a MappedKeyMapContainerPolicy

Converters will be supported in the case of an AbstractDirectMapping in the same way as if it were a normal AbstractDirectMapping

Container Policy Hierarchy

MappedKeyMapContainerPolicy

A new subclass of MapContainerPolicy will be added called MappedKeyMapContainerPolicy. This class will contain the logic necessary to deal with keys in mappings. It will contain the following references:

  • keyMapping - a MapKeyMapping that represents the key of for the Map
  • valueMapping - a MapComponentMapping that is a back pointer to the collection policy's owner

MappedKeyMapContainerPolicy will abstract the functions relating to the map. For instance:

  • adding to the map
  • augmenting selection, insert and delete queries for the collection policy's owner to make the map-aware
  • cloning the map

Iteration

ContainerPolicy provides an abstraction that allows you to iterate through the collection the ContainerPolicy represents. This abstraction will be extended. With the addition of CollectionTableMapMapping, it is necessary to iterate over collections that may contain a key-value pair rather than a single value. The iterator abstraction will have support added that allows iteration through collections that contain key-value pairs. The functionality will be kept as transparent as possible, users of this iterator abstraction will all have to be updated to consider the fact that the values they iterate through could potentially be a key value pair.

DirectMapMapping and ContainerPolicy

A new interface called DirectMapUsableContainerPolicy will be added. It will be implemented by the two ContainerPolicies that are eligable to be used with a DirectMapMapping, DirectMapContainerPolicy and MappedKeyMapContainerPolicy. This interface will provide a way to get common behavior from those container policies when dealing with the MapKey.

MappedKeyMapContainerPolicy is capable of providing all the functionality of DirectMapContainerPolicy. DirectMapContainerPolicy is being kept undeprecated because no EclipseLink deployment XML support is expected for MappedKeyMapContainerPolicy.

Change Sets

Change sets will be used for all changes. Functionality will be added to make uses of the newKey and oldKey instance variables in the existing change sets to deal with the keys.

Private Ownership

When a mapping with a MappedKeyContainerPolicy is setup as private owned, by default, the privateOwned setting will only affect the value in the map.

If the keyMapping on the MappedKeyContainerPolicy is set to privateOwned and refers to an Entity (OneToOneMapping), the removal of the key will also be triggered when a privateOwned relationship is severed.

Change Tracking

Under construction

Joining

When an attribute with a map is joined, the key will also be joined. Changes will be made to include the attributes of the map key in the joined query and to include the indices or the map key in the map key indices.

Cascading

JPA cascading will be supported by extending the methods that do cascading of remove, persistent and discovery to also include the map key through the container policy

Descriptor Iterator

Descriptor iteration will be modified to include the map key as the mapping including the key is iterated over

Events

pre and post events for Insert, Update and Delete will be propagated to the Map key as its owning mapping is inserted/updated/deleted.

Configuration

EclipseLink Public API

MappedKeyContainerPolicy

MappedKeyContainerPolicy contains 2 public methods:

  • setKeyMapping(MapKeyMapping) - sets the mapping that will represent the key of the map
  • setValueMapping(MapComponentMapping) - sets a pointer to the owning mapping

Both of these settings must be set on MappedKeyContainerPolicy for it to be used. Other than calling those methods on the MappedKeyContainerPolicy, configuration is the same as for a MapContainerPolicy.

MapKeyMapping/MapComponentMapping implementers

Direct implementers of MapComponentMapping (the mapping that owns the map) will have methods added that allow the table for the key to be set:

  • setKeyDataTable(DatabaseTable)
  • setKeyDataTableName(String)

Implementers of MapKeyMapping have no change in their public API.

MappedKeyContainerPolicy is enabled by simply setting the container policy on the appropriate mapping.

Samples

DirectCollectionMapping

       // SECTION: DIRECTCOLLECTIONMAPPING
       org.eclipse.persistence.mappings.DirectCollectionMapping directcollectionmapping = new org.eclipse.persistence.mappings.DirectCollectionMapping();
       directcollectionmapping.setAttributeName("directToDirectMap");
       directcollectionmapping.setIndirectionPolicy(new TransparentIndirectionPolicy());
       directcollectionmapping.setGetMethodName("getDirectToDirectMap");
       directcollectionmapping.setSetMethodName("setDirectToDirectMap");
       directcollectionmapping.setDirectFieldName("DIR_DIR_MAP_REL.MAP_VALUE");
       directcollectionmapping.setReferenceTableName("DIR_DIR_MAP_REL");
       directcollectionmapping.addReferenceKeyFieldName("DIR_DIR_MAP_REL.HOLDER_ID", "DIR_DIR_MAP_HOLDER.ID");
       
       org.eclipse.persistence.mappings.DirectToFieldMapping keyMapping = new org.eclipse.persistence.mappings.DirectToFieldMapping();
       keyMapping.setFieldName("DIR_DIR_MAP_REL.MAP_KEY");
       keyMapping.setDescriptor(descriptor);
       
       MappedKeyMapContainerPolicy policy = new MappedKeyMapContainerPolicy(IndirectMap.class);
       policy.setKeyMapping(keyMapping);
       policy.setValueMapping(directcollectionmapping);
       directcollectionmapping.setContainerPolicy(policy);


AggregateCollectionMapping

       // SECTION: AGGREGATECOLLECTIONMAPPING
       org.eclipse.persistence.mappings.AggregateCollectionMapping aggregatecollectionmapping = new org.eclipse.persistence.mappings.AggregateCollectionMapping();
       aggregatecollectionmapping.setAttributeName("aggregateToAggregateMap");
       aggregatecollectionmapping.setUsesIndirection(false);
       aggregatecollectionmapping.setGetMethodName("getAggregateToAggregateMap");
       aggregatecollectionmapping.setSetMethodName("setAggregateToAggregateMap");
       aggregatecollectionmapping.setReferenceClass(AggregateMapValue.class);
       aggregatecollectionmapping.addTargetForeignKeyFieldName("AGG_AGG_MAP_REL.HOLDER_ID", "AGG_AGG_MAP_HOLDER.ID");
       aggregatecollectionmapping.addFieldNameTranslation("AGG_AGG_MAP_REL.MAP_VALUE", "value->DIRECT");
       descriptor.addMapping(aggregatecollectionmapping);
       
       AggregateObjectMapping keyMapping = new AggregateObjectMapping();
       keyMapping.setReferenceClass(AggregateMapKey.class);
       keyMapping.addFieldNameTranslation("AGG_AGG_MAP_REL.MAP_KEY", "key->DIRECT");
       keyMapping.setDescriptor(descriptor);
       
       MappedKeyMapContainerPolicy policy = new MappedKeyMapContainerPolicy(IndirectMap.class);
       policy.setKeyMapping(keyMapping);
       policy.setValueMapping(aggregatecollectionmapping);
       aggregatecollectionmapping.setContainerPolicy(policy);

ManyToManyMapping


       ManyToManyMapping mapMapping = new ManyToManyMapping();
       mapMapping.setAttributeName("entityToEntityMap");
       mapMapping.setUsesIndirection(false);
       mapMapping.setReferenceClass(EntityMapValue.class);
       mapMapping.setRelationTableName("ENT_ENT_MAP_REL");
       mapMapping.setGetMethodName("getEntityToEntityMap");
       mapMapping.setSetMethodName("setEntityToEntityMap");
       mapMapping.addSourceRelationKeyFieldName("ENT_ENT_MAP_REL.HOLDER_ID", "ENT_ENT_MAP_HOLDER.ID");
       mapMapping.addTargetRelationKeyFieldName("ENT_ENT_MAP_REL.VALUE_ID", "ENT_MAP_VALUE.ID");
       
       org.eclipse.persistence.mappings.OneToOneMapping keyMapping = new org.eclipse.persistence.mappings.OneToOneMapping();
       keyMapping.setReferenceClass(EntityMapKey.class);
       keyMapping.addForeignKeyFieldName("ENT_ENT_MAP_REL.KEY_ID", "ENT_MAP_KEY.ID");
       keyMapping.setDescriptor(descriptor);
       
       MappedKeyMapContainerPolicy policy = new MappedKeyMapContainerPolicy(HashMap.class);
       policy.setKeyMapping(keyMapping);
       policy.setValueMapping(mapMapping);
       mapMapping.setContainerPolicy(policy);

JPA Configuration

JPA configuration will be defined by the specification. A brief overview to come.

Supported Features

The following will be supported for CollectionTableMapMapping:

  • Basic key / value.
  • Embeddable key / value.
  • Entity key/ value.
  • JPA Annotation config.
  • JPA XML config.

The following will currently not be supported for CollectionTableMapMapping:

  • native XML config.
  • MW support.

Open Issues

  • Which advanced features must be supported?
    • History Policy
    • Batch reading
    • Cascaded locking
  • JPQL updates are planned as a separate enhancement

Archived Initial Design

The initial design involved a much more all-encompassing mapping that would hold a mapping for the key and for the value. Although this would likely be somewhat easier to configure for users using proprietary-EclipseLink API, it was decided that this configuration benefit is less visible because of the JPA configuration options. Additionally, having a new kind of MapContainerPolicy allows us make use of some of the already existing behavior in existing EclipseLink mappings.

Feedback

CollectionTableMapMapping will be any Map mapping that contains either part of it's key or part of its value in a CollectionTable. Much of CollectionTableMapMapping's functionality will be similar to ManyToManyMapping because of the fact that both mappings use a relation table.

Mapping Hierarchy

The mapping hierarchy will be updated to include new abstract class RelationTableMapping with two subclasses, ManyToManyMapping and CollectionTableMapMapping.

RelationTableMapping

RelationTableMapping will contain a large portion of the code that is now contained in ManyToManyMapping. It will be responsible for everything on the source side of the relationship:

  • It will hold the insert, update and delete queries for the mapping
  • It will contain the keys for source side of the relationship
  • It will provide the framework that allows its subclasses to work
  • Public API will include any methods from ManyToManyMapping that are refacted into RelationTableMapping

ManyToManyMapping

ManyToManyMapping will now inherit from RelationTableMapping, and now contain the information and functionality to cope with the target part of the relationship.

  • It will contain the target keys
  • It will initialize the queries stored in its parent class
  • It will manage the target side of the relationship
  • Public API will be the same as current ManyToManyMapping

CollectionTableMapMapping

The new CollectionTableMapMapping class will be added as a subclass of RelationTableMapping. It will store the mappings for the key and the value of the map.

  • It will contain a mapping related to the key and one related to the value of the map
  • It will initialize the mappings it holds and the queries stored in its superclass
  • It will provide the functionality needed to deal with multiple mappings for the target
  • It will delegate much of the functionality related to its keys and values to its contained mappings
  • When the key is not an Entity, a single selection query is run. When the key is an Entity, an extra query is required to get the key.

Public API: (under construction)

  • MapComponentMapping getKeyMapping()
  • setKeyMapping(MapComponentMapping)
  • MapComponentMapping getValueMapping()
  • setValueMapping(MapComponentMapping)

MapComponentMapping

A new interface will be created call MapComponentMapping. This interface will provide the API that mapping that can be either the key or the value for a CollectionTableMapMapping must implement. The following mappings will implement this interface:

  • AbstractDirectMapping
  • AggregateObjectMapping
  • OneToOneMapping

Only MapComponentMappings will be eligible as the key or value of a CollectionTableMapMapping. It will abstract the following funtionality:

  • Adding required fields to selectionQuery, insertQuery, deleteQuery for the owning mapping
  • Extracting results of queries and using them to build the target
  • Cloning the target
  • Initiailization
  • Attribute Accessors for these mappings will not be used

Container Policy Hierarchy

A new subclass of MapContainerPolicy will be added called CollectionTableMapContainerPolicy.

CollectionTableMapContainerPolicy

CollectionTableMapContainerPolicy is a new subclass of MapContainerPolicy that allows map components to be derived from mappings instead of from objects.

  • Contains a reference to its owning mapping key mapping and value mapping
  • Overrides parent funtionality to allow the key mapping and value mapping to be considered when adding to a map

Iteration

ContainerPolicy provides an abstraction that allows you to iterate through the collection the ContainerPolicy represents. This abstraction will be extended. With the addition of CollectionTableMapMapping, it is necessary to iterate over collections that may contain a key-value pair rather than a single value. The iterator abstraction will have support added that allows iteration through collections that contain key-value pairs. The functionality will be kept as transparent as possible, users of this iterator abstraction will all have to be updated to consider the fact that the values they iterate through could potentially be a key value pair.