/** * PUBLIC: * Define the foreign key relationship in the 1-1 mapping. * This method is used for composite foreign key relationships, * that is the source object's table has multiple foreign key fields to * the target object's primary key fields. * Both the source foreign key field and the target foreign key field must * be specified. * When a foreign key is specified TopLink will automatically populate the * value for that field from the target object when the object is written to * the database. If the foreign key is also mapped through a direct-to-field * then the direct-to-field must be set read-only. */ @Override public void addForeignKeyField(DatabaseField sourceForeignKeyField, DatabaseField targetPrimaryKeyField) { setIsForeignKeyRelationship(true); getForeignKeyFields().addElement(sourceForeignKeyField); getSourceToTargetKeyFields().put(sourceForeignKeyField, targetPrimaryKeyField); getTargetToSourceKeyFields().put(targetPrimaryKeyField, sourceForeignKeyField); }
/** * INTERNAL: * Return the class this key mapping maps or the descriptor for it * @return */ public Class getMapKeyTargetType(){ return getReferenceClass(); }
/** * INTERNAL: * Return the selection criteria necessary to select the target object when this mapping * is a map key. * @return */ public Expression getAdditionalSelectionCriteriaForMapKey(){ return buildSelectionCriteria(false, false); }
/** * Return the appropriate map that maps the "foreign keys" * to the "primary keys". */ protected Map getForeignKeysToPrimaryKeys() { if (this.isForeignKeyRelationship()) { return this.getSourceToTargetKeyFields(); } else { return this.getTargetToSourceKeyFields(); } }
/** * Return the descriptor for whichever side of the * relation has the "primary key". */ protected ClassDescriptor getPrimaryKeyDescriptor() { if (this.isForeignKeyRelationship()) { return this.getReferenceDescriptor(); } else { return this.getDescriptor(); } }
public void initialize(AbstractSession session) throws DescriptorException { if (session.hasBroker()) { if (getReferenceClass() == null) { throw DescriptorException.referenceClassNotSpecified(this); session = session.getBroker().getSessionForClass(getReferenceClass()); if (isForeignKeyRelationship() && !isMapKeyMapping()) { getDescriptor().addPreDeleteMapping(this); for (DatabaseField field : getForeignKeyFields()) { DatabaseField builtField = getDescriptor().buildField(field, keyTableForMapKey); updateInsertableAndUpdatableFields(builtField); } else { updateInsertableAndUpdatableFields(field); if (this.mechanism.hasRelationTable()) { if(!this.foreignKeyFields.isEmpty() || !this.sourceToTargetKeyFields.isEmpty() || !this.targetToSourceKeyFields.isEmpty()) { throw DescriptorException.oneToOneMappingConflict(this.getDescriptor(), this); for (int index = 0; index < getForeignKeyFields().size(); index++) { DatabaseField foreignKeyField = getForeignKeyFields().get(index); foreignKeyField = getDescriptor().buildField(foreignKeyField, keyTableForMapKey); getForeignKeyFields().set(index, foreignKeyField); if (!(getTargetToSourceKeyFields().isEmpty() && getSourceToTargetKeyFields().isEmpty())) { if (getTargetToSourceKeyFields().isEmpty() || getSourceToTargetKeyFields().isEmpty()) {
if(this.mechanism.hasRelationTable()) { if(!this.foreignKeyFields.isEmpty() || !this.sourceToTargetKeyFields.isEmpty() || !this.targetToSourceKeyFields.isEmpty()) { throw DescriptorException.oneToOneMappingConflict(this.getDescriptor(), this); for (int index = 0; index < getForeignKeyFields().size(); index++) { DatabaseField foreignKeyField = getForeignKeyFields().get(index); foreignKeyField = getDescriptor().buildField(foreignKeyField, keyTableForMapKey); getForeignKeyFields().set(index, foreignKeyField); if (!(getTargetToSourceKeyFields().isEmpty() && getSourceToTargetKeyFields().isEmpty())) { if (getTargetToSourceKeyFields().isEmpty() || getSourceToTargetKeyFields().isEmpty()) { initializeForeignKeysWithDefaults(session); } else { initializeForeignKeys(session); if (shouldInitializeSelectionCriteria()) { if (shouldForceInitializationOfSelectionCriteria()) { setSelectionCriteria(buildSelectionCriteria()); } else { setSelectionCriteria(buildSelectionCriteria(true, true)); setShouldVerifyDelete(false); setFields(collectFields()); if (getReferenceDescriptor() != null && getReferenceDescriptor().hasTablePerClassPolicy()) { getReferenceDescriptor().getTablePerClassPolicy().prepareChildrenSelectionQuery(this, session);
/** * INTERNAL: * The foreign keys primary keys are stored as database fields in the map. */ protected void initializeForeignKeys(AbstractSession session) { HashMap<DatabaseField, DatabaseField> newSourceToTargetKeyFields = new HashMap(getSourceToTargetKeyFields().size()); HashMap<DatabaseField, DatabaseField> newTargetToSourceKeyFields = new HashMap(getTargetToSourceKeyFields().size()); Iterator<Map.Entry<DatabaseField, DatabaseField>> iterator = getSourceToTargetKeyFields().entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<DatabaseField, DatabaseField> entry = iterator.next(); DatabaseField sourceField = entry.getKey(); sourceField = getDescriptor().buildField(sourceField, keyTableForMapKey); DatabaseField targetField = entry.getValue(); targetField = getReferenceDescriptor().buildField(targetField, keyTableForMapKey); newSourceToTargetKeyFields.put(sourceField, targetField); newTargetToSourceKeyFields.put(targetField, sourceField); } setSourceToTargetKeyFields(newSourceToTargetKeyFields); setTargetToSourceKeyFields(newTargetToSourceKeyFields); }
dm.setAttributeName(extensionPropertyName); dm.setReferenceClass(extensionEntityClass); dm.setDescriptor(entityDescriptor); dm.setIsPrivateOwned(true); dm.setJoinFetch(ForeignReferenceMapping.OUTER_JOIN); dm.setCascadeAll(true); dm.setIsLazy(false); dm.dontUseIndirection(); dm.setIsOneToOneRelationship(true); dm.setRequiresTransientWeavedFields(false); dm.setMappedBy(inverse.getAttributeName()); for (DatabaseField sourceField : inverse.getSourceToTargetKeyFields().keySet()) { DatabaseField targetField = inverse.getSourceToTargetKeyFields().get(sourceField); dm.addTargetForeignKeyField(sourceField, targetField); dm.preInitialize(getEclipseLinkEntityManager().getDatabaseSession()); dm.initialize(getEclipseLinkEntityManager().getDatabaseSession()); entityDescriptor.addMapping(dm); entityDescriptor.getObjectBuilder().initialize(getEclipseLinkEntityManager().getDatabaseSession());
public void setAttributeValueInObject(Object object, Object value) { OneToOneMapping mapping = (OneToOneMapping)object; List associations = (List)value; mapping.setSourceToTargetKeyFields(new HashMap(associations.size() + 1)); mapping.setTargetToSourceKeyFields(new HashMap(associations.size() + 1)); Iterator iterator = associations.iterator(); while (iterator.hasNext()) { Association association = (Association)iterator.next(); mapping.getSourceToTargetKeyFields().put((DatabaseField)association.getKey(), (DatabaseField)association.getValue()); mapping.getTargetToSourceKeyFields().put((DatabaseField)association.getValue(), (DatabaseField)association.getKey()); } } });
/** * INTERNAL: * Selection criteria is created with source foreign keys and target keys. */ protected void initializePrivateOwnedCriteria() { if (!isForeignKeyRelationship()) { setPrivateOwnedCriteria(getSelectionCriteria()); } else { Expression pkCriteria = getDescriptor().getObjectBuilder().getPrimaryKeyExpression(); ExpressionBuilder builder = new ExpressionBuilder(); Expression backRef = builder.getManualQueryKey(getAttributeName() + "-back-ref", getDescriptor()); Expression newPKCriteria = pkCriteria.rebuildOn(backRef); Expression twistedSelection = backRef.twist(getSelectionCriteria(), builder); if (getDescriptor().getQueryManager().getAdditionalJoinExpression() != null) { // We don't have to twist the additional join because it's all against the same node, which is our base // but we do have to rebuild it onto the manual query key Expression rebuiltAdditional = getDescriptor().getQueryManager().getAdditionalJoinExpression().rebuildOn(backRef); if (twistedSelection == null) { twistedSelection = rebuiltAdditional; } else { twistedSelection = twistedSelection.and(rebuiltAdditional); } } setPrivateOwnedCriteria(newPKCriteria.and(twistedSelection)); } }
/** * INTERNAL: * Prepare a cascade locking policy. */ public void prepareCascadeLockingPolicy() { CascadeLockingPolicy policy = new CascadeLockingPolicy(getDescriptor(), getReferenceDescriptor()); policy.setQueryKeyFields(getSourceToTargetKeyFields(), ! isForeignKeyRelationship()); getReferenceDescriptor().addCascadeLockingPolicy(policy); }
/** * INTERNAL: * Create a query key that links to the map key * @return */ public QueryKey createQueryKeyForMapKey(){ OneToOneQueryKey key = new OneToOneQueryKey(); key.setDescriptor(getReferenceDescriptor()); key.setReferenceClass(getReferenceClass()); key.setJoinCriteria(getAdditionalSelectionCriteriaForMapKey()); return key; }
/** * INTERNAL: * Extract the fields for the Map key from the object to use in a query */ public Map extractIdentityFieldsForQuery(Object object, AbstractSession session){ Map keyFields = new HashMap(); for (int index = 0; index < getForeignKeyFields().size(); index++) { DatabaseField targetRelationField = getForeignKeyFields().elementAt(index); DatabaseField targetKey = getSourceToTargetKeyFields().get(targetRelationField); Object value = getReferenceDescriptor().getObjectBuilder().extractValueFromObjectForField(object, targetKey, session); keyFields.put(targetRelationField, value); } return keyFields; }
/** * INTERNAL: * Called only if both * shouldExtendPessimisticLockScope and shouldExtendPessimisticLockScopeInSourceQuery are true. * Adds fields to be locked to the where clause of the source query. * Note that the sourceQuery must be ObjectLevelReadQuery so that it has ExpressionBuilder. * * This method must be implemented in subclasses that allow * setting shouldExtendPessimisticLockScopeInSourceQuery to true. */ public void extendPessimisticLockScopeInSourceQuery(ObjectLevelReadQuery sourceQuery) { Expression exp = sourceQuery.getSelectionCriteria(); if(this.mechanism == null) { ExpressionBuilder builder = sourceQuery.getExpressionBuilder(); Iterator<Map.Entry<DatabaseField, DatabaseField>> it = this.getSourceToTargetKeyFields().entrySet().iterator(); Map.Entry<DatabaseField, DatabaseField> entry = it.next(); exp = builder.getField(entry.getKey()).equal(builder.get(this.getAttributeName()).getField(entry.getValue())).and(exp); } else { exp = this.mechanism.joinRelationTableField(exp, sourceQuery.getExpressionBuilder()); } sourceQuery.setSelectionCriteria(exp); }
protected void addOneToOneMappingLines(NonreflectiveMethodDefinition method, String mappingName, OneToOneMapping mapping) { for (Iterator foreignKeysEnum = mapping.getSourceToTargetKeyFields().keySet().iterator(); foreignKeysEnum.hasNext();) { DatabaseField sourceField = (DatabaseField)foreignKeysEnum.next(); DatabaseField targetField = mapping.getSourceToTargetKeyFields().get(sourceField); if (mapping.getForeignKeyFields().contains(sourceField)) { method.addLine(mappingName + ".addForeignKeyFieldName(\"" + sourceField.getQualifiedName() + "\", \"" + targetField.getQualifiedName() + "\");"); } else { method.addLine(mappingName + ".addTargetForeignKeyFieldName(\"" + targetField.getQualifiedName() + "\", \"" + sourceField.getQualifiedName() + "\");"); } } if (!mapping.shouldVerifyDelete()) { method.addLine(mappingName + ".setShouldVerifyDelete(false);"); } }
/** * INTERNAL: * This method is used to update the table per tenant descriptor with * a table per tenant schema. This includes any relation tables from * mappings. This will be done through the setting of a table qualifier on * the tables. * * This method should only be called at the start of a client session * lifecycle and should only be called once. */ protected void setTableSchemaPerTenant() { descriptor.setTableQualifier(contextTenant); // Any mapping with a relation table will need to be updated. for (DatabaseMapping mapping : descriptor.getMappings()) { if (mapping.isManyToManyMapping()) { ((ManyToManyMapping) mapping).getRelationTable().setTableQualifier(contextTenant); } else if (mapping.isOneToOneMapping() && ((OneToOneMapping) mapping).hasRelationTable()) { ((OneToOneMapping) mapping).getRelationTable().setTableQualifier(contextTenant); } else if (mapping.isDirectCollectionMapping()) { ((DirectCollectionMapping) mapping).getReferenceTable().setTableQualifier(contextTenant); } } }
/** * INTERNAL: * Return the fields that make up the identity of the mapped object. For mappings with * a primary key, it will be the set of fields in the primary key. For mappings without * a primary key it will likely be all the fields * @return */ public List<DatabaseField> getIdentityFieldsForMapKey(){ return getForeignKeyFields(); }
((ManyToManyMapping) mapping).setRelationTable(updateTable(((ManyToManyMapping) mapping).getRelationTable())); } else if (mapping.isOneToOneMapping() && ((OneToOneMapping) mapping).hasRelationTable()) { ((OneToOneMapping) mapping).setRelationTable(updateTable(((OneToOneMapping) mapping).getRelationTable())); } else if (mapping.isDirectCollectionMapping()) { ((DirectCollectionMapping) mapping).setReferenceTable(updateTable(((DirectCollectionMapping) mapping).getReferenceTable()));
/** * INTERNAL: * Get all the fields for the map key */ public List<DatabaseField> getAllFieldsForMapKey(){ List<DatabaseField> fields = new ArrayList(getReferenceDescriptor().getAllFields().size() + getForeignKeyFields().size()); fields.addAll(getReferenceDescriptor().getAllFields()); fields.addAll(getForeignKeyFields()); return fields; }