Search in sources :

Example 1 with JoinColumnMetadata

use of org.eclipse.persistence.internal.jpa.metadata.columns.JoinColumnMetadata in project eclipselink by eclipse-ee4j.

the class MappingAccessor method processEntityMapKeyClass.

/**
 * INTERNAL:
 * Process the map key to be an entity class.
 */
protected OneToOneMapping processEntityMapKeyClass(MappedKeyMapAccessor mappedKeyMapAccessor) {
    String mapKeyClassName = mappedKeyMapAccessor.getMapKeyClass().getName();
    // Create the one to one map key mapping.
    OneToOneMapping keyMapping = new OneToOneMapping();
    keyMapping.setReferenceClassName(mapKeyClassName);
    keyMapping.dontUseIndirection();
    keyMapping.setDescriptor(getDescriptor().getClassDescriptor());
    // Process the map key join columns.
    EntityAccessor mapKeyAccessor = getProject().getEntityAccessor(mapKeyClassName);
    MetadataDescriptor mapKeyClassDescriptor = mapKeyAccessor.getDescriptor();
    // If the fk field (name) is not specified, it defaults to the
    // concatenation of the following: the name of the referencing
    // relationship property or field of the referencing entity or
    // embeddable; "_"; "KEY"
    String defaultFKFieldName = getAttributeName() + DEFAULT_MAP_KEY_COLUMN_SUFFIX;
    // Get the join columns (directly or through an association override),
    // init them and validate.
    List<JoinColumnMetadata> joinColumns = getJoinColumns(mappedKeyMapAccessor.getMapKeyJoinColumns(), mapKeyClassDescriptor);
    // Get the foreign key (directly or through an association override) and
    // make sure it is initialized for processing.
    ForeignKeyMetadata foreignKey = getForeignKey(mappedKeyMapAccessor.getMapKeyForeignKey(), mapKeyClassDescriptor);
    // Now process the foreign key relationship metadata.
    processForeignKeyRelationship(keyMapping, joinColumns, foreignKey, mapKeyClassDescriptor, defaultFKFieldName, getDefaultTableForEntityMapKey());
    return keyMapping;
}
Also used : EntityAccessor(org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor) ForeignKeyMetadata(org.eclipse.persistence.internal.jpa.metadata.columns.ForeignKeyMetadata) MetadataDescriptor(org.eclipse.persistence.internal.jpa.metadata.MetadataDescriptor) JoinColumnMetadata(org.eclipse.persistence.internal.jpa.metadata.columns.JoinColumnMetadata) OneToOneMapping(org.eclipse.persistence.mappings.OneToOneMapping)

Example 2 with JoinColumnMetadata

use of org.eclipse.persistence.internal.jpa.metadata.columns.JoinColumnMetadata in project eclipselink by eclipse-ee4j.

the class ElementCollectionAccessor method processCollectionTable.

/**
 * INTERNAL:
 * Process a MetadataCollectionTable.
 */
@Override
protected void processCollectionTable(CollectionMapping mapping) {
    super.processCollectionTable(mapping);
    // column validation is performed in the getJoinColumns call.
    for (JoinColumnMetadata joinColumn : getJoinColumnsAndValidate(getCollectionTable().getJoinColumns(), getOwningDescriptor())) {
        // Look up the primary key field from the referenced column name.
        DatabaseField pkField = getReferencedField(joinColumn.getReferencedColumnName(), getOwningDescriptor(), MetadataLogger.PK_COLUMN, mapping.isAggregateCollectionMapping());
        // The default name is the primary key of the owning entity.
        DatabaseField fkField = joinColumn.getForeignKeyField(pkField);
        setFieldName(fkField, getOwningDescriptor().getAlias() + "_" + getOwningDescriptor().getPrimaryKeyFieldName(), MetadataLogger.FK_COLUMN);
        fkField.setTable(getReferenceDatabaseTable());
        if (mapping.isDirectCollectionMapping()) {
            // Add the reference key field for the direct collection mapping.
            ((DirectCollectionMapping) mapping).addReferenceKeyField(fkField, pkField);
        } else {
            mapping.addTargetForeignKeyField(fkField, pkField);
        }
    }
    if (m_deleteAll != null && mapping.isPrivateOwned()) {
        mapping.setMustDeleteReferenceObjectsOneByOne(!m_deleteAll);
    }
}
Also used : DatabaseField(org.eclipse.persistence.internal.helper.DatabaseField) JoinColumnMetadata(org.eclipse.persistence.internal.jpa.metadata.columns.JoinColumnMetadata) DirectCollectionMapping(org.eclipse.persistence.mappings.DirectCollectionMapping)

Example 3 with JoinColumnMetadata

use of org.eclipse.persistence.internal.jpa.metadata.columns.JoinColumnMetadata in project eclipselink by eclipse-ee4j.

the class OneToManyAccessor method processUnidirectionalOneToManyTargetForeignKeyRelationship.

/**
 * INTERNAL:
 * Process the join column(s) metadata for the owning side of a
 * unidirectional one to many mapping. The default pk used only with single
 * primary key  entities. The processor should never get as far as to use
 * them with entities that have a composite primary key (validation
 * exception will be thrown).
 */
protected void processUnidirectionalOneToManyTargetForeignKeyRelationship(UnidirectionalOneToManyMapping mapping, List<JoinColumnMetadata> joinColumns, MetadataDescriptor owningDescriptor) {
    // If the fk field (name) is not specified, it defaults to the
    // concatenation of the following: the name of the referencing
    // relationship property or field of the referencing entity; "_";
    // the name of the referenced primary key column.
    String defaultFKFieldName = getDefaultAttributeName() + "_" + owningDescriptor.getPrimaryKeyFieldName();
    // Add the source foreign key fields to the mapping.
    for (JoinColumnMetadata joinColumn : joinColumns) {
        // Look up the primary key field from the referenced column name.
        DatabaseField pkField = getReferencedField(joinColumn.getReferencedColumnName(), owningDescriptor, MetadataLogger.PK_COLUMN);
        DatabaseField fkField = joinColumn.getForeignKeyField(pkField);
        setFieldName(fkField, defaultFKFieldName, MetadataLogger.FK_COLUMN);
        // Set the table name if one is not already set.
        if (!fkField.hasTableName()) {
            fkField.setTable(getReferenceDescriptor().getPrimaryTable());
        }
        // Uni-directional 12M mapping would like a type on the foreign key
        // field. If one is not set, a unidirectional one to many mapping
        // will try to set one itself in its postInitialize. There is
        // currently a bug against this since the postInitiaze does not
        // handle the fact that the descriptor may be an aggregate, hence
        // not be able to look up a primary key mapping correctly.
        // From a metadata processing standpoint, we'll attempt to make sure
        // one is set. Meaning in some cases we won't be able to if we don't
        // have an associated mapping accessor for the pkField. So why
        // wouldn't we? One, it could be a bogus field specified only for
        // testing purposes to ensure an override is correctly applied and
        // two, the field could be part of a derived id (which at this point
        // we don't have the mapping accessor readily accessible. (may be
        // able to fix this if it becomes a problem). And thirdly, there is
        // the 'off' chance we've screwed up metadata processing somewhere
        // ( yeah right! ) so instead of show casing our mistakes, let's
        // hide them! :-) Anyway, long story short, if there is no
        // mappingAccessor for the pkField, don't do anything and silently
        // continue. Best we can do right now ...
        MappingAccessor mappingAccessor = owningDescriptor.getPrimaryKeyAccessorForField(pkField);
        if (mappingAccessor != null) {
            // If the mapping specified a converter then the field
            // classification may be set so check it first.
            Class<?> fieldClassification = mappingAccessor.getMapping().getFieldClassification(mappingAccessor.getMapping().getField());
            String typeName;
            if (fieldClassification == null) {
                // No fieldClassification, use the raw class from the
                // mapping accessor.
                typeName = mappingAccessor.getRawClass().getName();
            } else {
                typeName = fieldClassification.getName();
            }
            fkField.setTypeName(typeName);
        }
        // Add target foreign key to the mapping.
        mapping.addTargetForeignKeyField(fkField, pkField);
        // mapping to be read only.
        if (fkField.isReadOnly()) {
            mapping.setIsReadOnly(true);
        }
    }
}
Also used : DatabaseField(org.eclipse.persistence.internal.helper.DatabaseField) JoinColumnMetadata(org.eclipse.persistence.internal.jpa.metadata.columns.JoinColumnMetadata)

Example 4 with JoinColumnMetadata

use of org.eclipse.persistence.internal.jpa.metadata.columns.JoinColumnMetadata in project eclipselink by eclipse-ee4j.

the class MappingAccessor method getJoinColumnsAndValidate.

/**
 * INTERNAL:
 * This method will validate the join columns and default any where
 * necessary.
 */
protected List<JoinColumnMetadata> getJoinColumnsAndValidate(List<JoinColumnMetadata> joinColumns, MetadataDescriptor referenceDescriptor) {
    if (joinColumns.isEmpty()) {
        if (referenceDescriptor.hasCompositePrimaryKey()) {
            // key. Foreign and primary key to have the same name.
            for (DatabaseField primaryKeyField : referenceDescriptor.getPrimaryKeyFields()) {
                // Multitenant primary key fields will be dealt with below so avoid adding here.
                if (!primaryKeyField.isPrimaryKey()) {
                    JoinColumnMetadata joinColumn = new JoinColumnMetadata();
                    joinColumn.setReferencedColumnName(primaryKeyField.getName());
                    joinColumn.setName(primaryKeyField.getName());
                    joinColumn.setProject(referenceDescriptor.getProject());
                    joinColumns.add(joinColumn);
                }
            }
        } else {
            // Add a default one for the single case, not setting any
            // foreign and primary key names. They will default based
            // on which accessor is using them.
            JoinColumnMetadata jcm = new JoinColumnMetadata();
            jcm.setProject(referenceDescriptor.getProject());
            joinColumns.add(jcm);
        }
    } else {
        // an inheritance subclass.
        for (JoinColumnMetadata joinColumn : joinColumns) {
            // Doing this could potentially change a value entered in XML.
            // However, in this case I think that is ok since in theory we
            // are writing out the correct value that EclipseLink needs to
            // form valid queries.
            String referencedColumnName = joinColumn.getReferencedColumnName();
            // code.
            if (referencedColumnName != null && !isVariableOneToOne()) {
                DatabaseField referencedField = new DatabaseField();
                setFieldName(referencedField, referencedColumnName);
                joinColumn.setReferencedColumnName(referenceDescriptor.getPrimaryKeyJoinColumnAssociation(referencedField).getName());
            }
        }
    }
    // in metadata.
    if (referenceDescriptor.hasSingleTableMultitenant() && joinColumns.size() != referenceDescriptor.getPrimaryKeyFields().size()) {
        Map<String, List<DatabaseField>> referenceTenantFields = referenceDescriptor.getSingleTableMultitenantFields();
        // If we are multitenant then we can sync up on relationship fields
        // using the context property.
        Map<String, List<DatabaseField>> tenantFields = getDescriptor().hasSingleTableMultitenant() ? getDescriptor().getSingleTableMultitenantFields() : null;
        for (String contextProperty : referenceTenantFields.keySet()) {
            List<DatabaseField> referenceFields = referenceTenantFields.get(contextProperty);
            for (DatabaseField referenceField : referenceFields) {
                // care about it.
                if (referenceField.isPrimaryKey()) {
                    JoinColumnMetadata jcm = new JoinColumnMetadata();
                    // This join column must be read only.
                    jcm.setInsertable(false);
                    jcm.setUpdatable(false);
                    // field that matches from it.
                    if (tenantFields != null && tenantFields.containsKey(contextProperty)) {
                        // This is going to return a list just pick the first
                        // field (they populate the same value so doesn't really
                        // matter which one we pick.
                        jcm.setName(tenantFields.get(contextProperty).get(0).getName());
                    } else {
                        // We don't have a match, use the same name.
                        jcm.setName(referenceField.getName());
                    }
                    jcm.setReferencedColumnName(referenceField.getName());
                    jcm.setProject(referenceDescriptor.getProject());
                    joinColumns.add(jcm);
                }
            }
        }
    }
    // Now run some validation.
    if (referenceDescriptor.hasCompositePrimaryKey()) {
        // The number of join columns should equal the number of primary key fields.
        if (joinColumns.size() != referenceDescriptor.getPrimaryKeyFields().size()) {
            throw ValidationException.incompleteJoinColumnsSpecified(getAnnotatedElement(), getJavaClass());
        }
        // All the primary and foreign key field names should be specified.
        for (JoinColumnMetadata joinColumn : joinColumns) {
            if (joinColumn.isPrimaryKeyFieldNotSpecified() || joinColumn.isForeignKeyFieldNotSpecified()) {
                throw ValidationException.incompleteJoinColumnsSpecified(getAnnotatedElement(), getJavaClass());
            }
        }
    }
    return joinColumns;
}
Also used : DatabaseField(org.eclipse.persistence.internal.helper.DatabaseField) JoinColumnMetadata(org.eclipse.persistence.internal.jpa.metadata.columns.JoinColumnMetadata) List(java.util.List) ArrayList(java.util.ArrayList)

Example 5 with JoinColumnMetadata

use of org.eclipse.persistence.internal.jpa.metadata.columns.JoinColumnMetadata in project eclipselink by eclipse-ee4j.

the class MappingAccessor method processForeignKeyRelationship.

/**
 * INTERNAL:
 * Process the join columns for the owning side of a one to one mapping.
 * The default pk and fk field names are used only with single primary key
 * entities. The processor should never get as far as to use them with
 * entities that have a composite primary key (validation exception will be
 * thrown).
 */
protected void processForeignKeyRelationship(ForeignReferenceMapping mapping, List<JoinColumnMetadata> joinColumns, ForeignKeyMetadata foreignKey, MetadataDescriptor referenceDescriptor, String defaultFKFieldName, DatabaseTable defaultFKTable) {
    // We need to know if all the mappings are read-only so we can determine
    // if we use target foreign keys to represent read-only parts of the
    // join, or if we simply set the whole mapping as read-only
    boolean allReadOnly = true;
    Map<DatabaseField, DatabaseField> fields = new HashMap<DatabaseField, DatabaseField>();
    List<String> sourceFields = new ArrayList<String>();
    List<String> targetFields = new ArrayList<String>();
    DatabaseTable targetTable = null;
    // Build our fk->pk associations.
    for (JoinColumnMetadata joinColumn : joinColumns) {
        // Look up the primary key field from the referenced column name.
        DatabaseField pkField = getReferencedField(joinColumn.getReferencedColumnName(), referenceDescriptor, MetadataLogger.PK_COLUMN);
        // The foreign key should be built using the primary key field
        // since it will contain extra metadata that can not be specified
        // in the join column. This will keep the pk and fk fields in sync.
        DatabaseField fkField = joinColumn.getForeignKeyField(pkField);
        setFieldName(fkField, defaultFKFieldName, MetadataLogger.FK_COLUMN);
        // Set the table name if one is not already set.
        if (!fkField.hasTableName()) {
            fkField.setTable(defaultFKTable);
        }
        fields.put(fkField, pkField);
        sourceFields.add(fkField.getName());
        targetFields.add(pkField.getName());
        if (targetTable == null) {
            targetTable = pkField.getTable();
        }
        allReadOnly = allReadOnly && fkField.isReadOnly();
    }
    DatabaseTable foreignKeyTable = null;
    // Apply the fields to the mapping based on what we found.
    for (DatabaseField fkField : fields.keySet()) {
        DatabaseField pkField = fields.get(fkField);
        if (allReadOnly || !fkField.isReadOnly()) {
            // Add a source foreign key to the mapping.
            mapping.addForeignKeyField(fkField, pkField);
        } else {
            // This is a read-only join column that is part of a set of join
            // columns that are not all read only - hence this is not a
            // read-only mapping, but instead uses a target foreign key
            // field to enable the read-only functionality
            mapping.addTargetForeignKeyField(pkField, fkField);
        }
        // Set the foreign key table to the first fk's table.
        if (foreignKeyTable == null) {
            foreignKeyTable = fkField.getTable();
        }
    }
    // If all the join columns are read-only then set the mapping as read only.
    mapping.setIsReadOnly(allReadOnly);
    // the fk's are on the target table as well.
    if (foreignKey != null) {
        foreignKey.process(foreignKeyTable, sourceFields, targetFields, targetTable);
    }
}
Also used : HashMap(java.util.HashMap) DatabaseField(org.eclipse.persistence.internal.helper.DatabaseField) ArrayList(java.util.ArrayList) DatabaseTable(org.eclipse.persistence.internal.helper.DatabaseTable) JoinColumnMetadata(org.eclipse.persistence.internal.jpa.metadata.columns.JoinColumnMetadata)

Aggregations

JoinColumnMetadata (org.eclipse.persistence.internal.jpa.metadata.columns.JoinColumnMetadata)10 DatabaseField (org.eclipse.persistence.internal.helper.DatabaseField)7 ForeignKeyMetadata (org.eclipse.persistence.internal.jpa.metadata.columns.ForeignKeyMetadata)3 ArrayList (java.util.ArrayList)2 PrimaryKeyJoinColumnMetadata (org.eclipse.persistence.internal.jpa.metadata.columns.PrimaryKeyJoinColumnMetadata)2 HashMap (java.util.HashMap)1 List (java.util.List)1 DatabaseTable (org.eclipse.persistence.internal.helper.DatabaseTable)1 MetadataDescriptor (org.eclipse.persistence.internal.jpa.metadata.MetadataDescriptor)1 EntityAccessor (org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor)1 PrimaryKeyForeignKeyMetadata (org.eclipse.persistence.internal.jpa.metadata.columns.PrimaryKeyForeignKeyMetadata)1 DirectCollectionMapping (org.eclipse.persistence.mappings.DirectCollectionMapping)1 OneToOneMapping (org.eclipse.persistence.mappings.OneToOneMapping)1