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;
}
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);
}
}
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);
}
}
}
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;
}
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);
}
}
Aggregations