Search in sources :

Example 16 with PersistableMapping

use of org.datanucleus.store.rdbms.mapping.java.PersistableMapping in project datanucleus-rdbms by datanucleus.

the class MapTable method getExpectedIndices.

/**
 * Accessor for the indices for this table.
 * This includes both the user-defined indices (via MetaData), and the ones required by foreign keys.
 * @param clr The ClassLoaderResolver
 * @return The indices
 */
protected Set getExpectedIndices(ClassLoaderResolver clr) {
    Set indices = new HashSet();
    // Index for FK back to owner
    if (mmd.getIndexMetaData() != null) {
        Index index = TableUtils.getIndexForField(this, mmd.getIndexMetaData(), ownerMapping);
        if (index != null) {
            indices.add(index);
        }
    } else if (mmd.getJoinMetaData() != null && mmd.getJoinMetaData().getIndexMetaData() != null) {
        Index index = TableUtils.getIndexForField(this, mmd.getJoinMetaData().getIndexMetaData(), ownerMapping);
        if (index != null) {
            indices.add(index);
        }
    } else {
        // Fallback to an index for the foreign-key to the owner
        Index index = TableUtils.getIndexForField(this, null, ownerMapping);
        if (index != null) {
            indices.add(index);
        }
    }
    // Index for the key FK (if required)
    if (keyMapping instanceof EmbeddedKeyPCMapping) {
        // Add all indices required by fields of the embedded key
        EmbeddedKeyPCMapping embMapping = (EmbeddedKeyPCMapping) keyMapping;
        for (int i = 0; i < embMapping.getNumberOfJavaTypeMappings(); i++) {
            JavaTypeMapping embFieldMapping = embMapping.getJavaTypeMapping(i);
            IndexMetaData imd = embFieldMapping.getMemberMetaData().getIndexMetaData();
            if (imd != null) {
                Index index = TableUtils.getIndexForField(this, imd, embFieldMapping);
                if (index != null) {
                    indices.add(index);
                }
            }
        }
    } else {
        KeyMetaData keymd = mmd.getKeyMetaData();
        if (keymd != null && keymd.getIndexMetaData() != null) {
            IndexMetaData idxmd = mmd.getKeyMetaData().getIndexMetaData();
            Index index = TableUtils.getIndexForField(this, idxmd, keyMapping);
            if (index != null) {
                indices.add(index);
            }
        } else {
            // Fallback to an index for any foreign-key to the key
            if (keyMapping instanceof PersistableMapping) {
                Index index = TableUtils.getIndexForField(this, null, keyMapping);
                if (index != null) {
                    indices.add(index);
                }
            }
        }
    }
    // Index for the value FK (if required)
    if (valueMapping instanceof EmbeddedValuePCMapping) {
        // Add all indices required by fields of the embedded value
        EmbeddedValuePCMapping embMapping = (EmbeddedValuePCMapping) valueMapping;
        for (int i = 0; i < embMapping.getNumberOfJavaTypeMappings(); i++) {
            JavaTypeMapping embFieldMapping = embMapping.getJavaTypeMapping(i);
            IndexMetaData imd = embFieldMapping.getMemberMetaData().getIndexMetaData();
            if (imd != null) {
                Index index = TableUtils.getIndexForField(this, imd, embFieldMapping);
                if (index != null) {
                    indices.add(index);
                }
            }
        }
    } else {
        ValueMetaData valmd = mmd.getValueMetaData();
        if (valmd != null && valmd.getIndexMetaData() != null) {
            IndexMetaData idxmd = mmd.getValueMetaData().getIndexMetaData();
            Index index = TableUtils.getIndexForField(this, idxmd, valueMapping);
            if (index != null) {
                indices.add(index);
            }
        } else {
            // Fallback to an index for any foreign-key to the value
            if (valueMapping instanceof PersistableMapping) {
                Index index = TableUtils.getIndexForField(this, null, valueMapping);
                if (index != null) {
                    indices.add(index);
                }
            }
        }
    }
    return indices;
}
Also used : PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) HashSet(java.util.HashSet) Set(java.util.Set) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) KeyMetaData(org.datanucleus.metadata.KeyMetaData) PrimaryKeyMetaData(org.datanucleus.metadata.PrimaryKeyMetaData) ForeignKeyMetaData(org.datanucleus.metadata.ForeignKeyMetaData) ValueMetaData(org.datanucleus.metadata.ValueMetaData) Index(org.datanucleus.store.rdbms.key.Index) EmbeddedValuePCMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedValuePCMapping) HashSet(java.util.HashSet) EmbeddedKeyPCMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedKeyPCMapping) IndexMetaData(org.datanucleus.metadata.IndexMetaData)

Example 17 with PersistableMapping

use of org.datanucleus.store.rdbms.mapping.java.PersistableMapping in project datanucleus-rdbms by datanucleus.

the class MapTable method initialize.

/**
 * Method to initialise the table definition.
 * @param clr The ClassLoaderResolver
 */
public void initialize(ClassLoaderResolver clr) {
    assertIsUninitialized();
    MapMetaData mapmd = mmd.getMap();
    if (mapmd == null) {
        throw new NucleusUserException(Localiser.msg("057017", mmd));
    }
    PrimaryKeyMetaData pkmd = (mmd.getJoinMetaData() != null ? mmd.getJoinMetaData().getPrimaryKeyMetaData() : null);
    boolean pkColsSpecified = (pkmd != null && pkmd.getColumnMetaData() != null);
    boolean pkRequired = requiresPrimaryKey();
    // Add owner mapping
    ColumnMetaData[] ownerColmd = null;
    if (mmd.getJoinMetaData() != null && mmd.getJoinMetaData().getColumnMetaData() != null && mmd.getJoinMetaData().getColumnMetaData().length > 0) {
        // Column mappings defined at this side (1-N, M-N)
        // When specified at this side they use the <join> tag
        ownerColmd = mmd.getJoinMetaData().getColumnMetaData();
    }
    ownerMapping = ColumnCreator.createColumnsForJoinTables(clr.classForName(ownerType), mmd, ownerColmd, storeMgr, this, pkRequired, false, FieldRole.ROLE_OWNER, clr, null);
    if (NucleusLogger.DATASTORE.isDebugEnabled()) {
        logMapping(mmd.getFullFieldName() + ".[OWNER]", ownerMapping);
    }
    String keyValueFieldName = (mmd.getKeyMetaData() != null ? mmd.getKeyMetaData().getMappedBy() : null);
    String valueKeyFieldName = (mmd.getValueMetaData() != null ? mmd.getValueMetaData().getMappedBy() : null);
    // Add key mapping
    boolean keyPC = (mmd.hasMap() && mmd.getMap().keyIsPersistent());
    Class keyCls = clr.classForName(mapmd.getKeyType());
    if (keyValueFieldName != null && isEmbeddedValuePC()) {
    // Added in value code
    } else if (isSerialisedKey() || isEmbeddedKeyPC() || (isEmbeddedKey() && !keyPC) || ClassUtils.isReferenceType(keyCls)) {
        // Key = PC(embedded), PC(serialised), Non-PC(serialised), Non-PC(embedded), Reference
        keyMapping = storeMgr.getMappingManager().getMapping(this, mmd, clr, FieldRole.ROLE_MAP_KEY);
        if (Boolean.TRUE.equals(mmd.getContainer().allowNulls())) {
            // Make all key col(s) nullable so we can store null elements
            for (int i = 0; i < keyMapping.getNumberOfDatastoreMappings(); i++) {
                Column elementCol = keyMapping.getDatastoreMapping(i).getColumn();
                elementCol.setNullable(true);
            }
        }
        if (NucleusLogger.DATASTORE.isDebugEnabled()) {
            logMapping(mmd.getFullFieldName() + ".[KEY]", keyMapping);
        }
        if (valueKeyFieldName != null && isEmbeddedKeyPC()) {
            // Key (PC) is embedded and value is a field of the key
            EmbeddedKeyPCMapping embMapping = (EmbeddedKeyPCMapping) keyMapping;
            valueMapping = embMapping.getJavaTypeMapping(valueKeyFieldName);
        }
    } else {
        // Key = PC
        ColumnMetaData[] keyColmd = null;
        KeyMetaData keymd = mmd.getKeyMetaData();
        if (keymd != null && keymd.getColumnMetaData() != null && keymd.getColumnMetaData().length > 0) {
            // Column mappings defined at this side (1-N, M-N)
            keyColmd = keymd.getColumnMetaData();
        }
        keyMapping = ColumnCreator.createColumnsForJoinTables(keyCls, mmd, keyColmd, storeMgr, this, false, false, FieldRole.ROLE_MAP_KEY, clr, null);
        if (mmd.getContainer().allowNulls() == Boolean.TRUE) {
            // Make all key col(s) nullable so we can store null elements
            for (int i = 0; i < keyMapping.getNumberOfDatastoreMappings(); i++) {
                Column elementCol = keyMapping.getDatastoreMapping(i).getColumn();
                elementCol.setNullable(true);
            }
        }
        if (NucleusLogger.DATASTORE.isDebugEnabled()) {
            logMapping(mmd.getFullFieldName() + ".[KEY]", keyMapping);
        }
    }
    // Add value mapping
    boolean valuePC = (mmd.hasMap() && mmd.getMap().valueIsPersistent());
    Class valueCls = clr.classForName(mapmd.getValueType());
    if (valueKeyFieldName != null && isEmbeddedKeyPC()) {
    // Added in key code
    } else if (isSerialisedValue() || isEmbeddedValuePC() || (isEmbeddedValue() && !valuePC) || ClassUtils.isReferenceType(valueCls)) {
        // Value = PC(embedded), PC(serialised), Non-PC(serialised), Non-PC(embedded), Reference
        valueMapping = storeMgr.getMappingManager().getMapping(this, mmd, clr, FieldRole.ROLE_MAP_VALUE);
        if (mmd.getContainer().allowNulls() == Boolean.TRUE) {
            // Make all value col(s) nullable so we can store null elements
            for (int i = 0; i < valueMapping.getNumberOfDatastoreMappings(); i++) {
                Column elementCol = valueMapping.getDatastoreMapping(i).getColumn();
                elementCol.setNullable(true);
            }
        }
        if (NucleusLogger.DATASTORE.isDebugEnabled()) {
            logMapping(mmd.getFullFieldName() + ".[VALUE]", valueMapping);
        }
        if (keyValueFieldName != null && isEmbeddedValuePC()) {
            // Value (PC) is embedded and key is a field of the value
            EmbeddedValuePCMapping embMapping = (EmbeddedValuePCMapping) valueMapping;
            keyMapping = embMapping.getJavaTypeMapping(keyValueFieldName);
        }
    } else {
        // Value = PC
        ColumnMetaData[] valueColmd = null;
        ValueMetaData valuemd = mmd.getValueMetaData();
        if (valuemd != null && valuemd.getColumnMetaData() != null && valuemd.getColumnMetaData().length > 0) {
            // Column mappings defined at this side (1-N, M-N)
            valueColmd = valuemd.getColumnMetaData();
        }
        valueMapping = ColumnCreator.createColumnsForJoinTables(clr.classForName(mapmd.getValueType()), mmd, valueColmd, storeMgr, this, false, true, FieldRole.ROLE_MAP_VALUE, clr, null);
        if (mmd.getContainer().allowNulls() == Boolean.TRUE) {
            // Make all value col(s) nullable so we can store null elements
            for (int i = 0; i < valueMapping.getNumberOfDatastoreMappings(); i++) {
                Column elementCol = valueMapping.getDatastoreMapping(i).getColumn();
                elementCol.setNullable(true);
            }
        }
        if (NucleusLogger.DATASTORE.isDebugEnabled()) {
            logMapping(mmd.getFullFieldName() + ".[VALUE]", valueMapping);
        }
    }
    // Add order mapping if required
    boolean orderRequired = false;
    if (mmd.getOrderMetaData() != null) {
        // User requested order column so add one
        orderRequired = true;
    } else if (requiresPrimaryKey() && !pkColsSpecified) {
        // PK is required so maybe need to add an index to form the PK
        if (isEmbeddedKeyPC()) {
            if (mmd.hasExtension("surrogate-pk-column") && mmd.getValueForExtension("surrogate-pk-column").equalsIgnoreCase("true")) {
                // Allow user to request surrogate pk column be added (for use with JPA)
                orderRequired = true;
            } else if (storeMgr.getApiAdapter().getName().equalsIgnoreCase("JDO") && mmd.getMap().getKeyClassMetaData(clr).getIdentityType() != IdentityType.APPLICATION) {
                // Embedded key PC with datastore id so we need an index to form the PK TODO It is arguable that we can just use all embedded key fields as part of PK here always
                orderRequired = true;
            }
        } else if (isSerialisedKey()) {
            // Serialised key, so need an index to form the PK
            orderRequired = true;
        } else if (keyMapping instanceof ReferenceMapping) {
            // ReferenceMapping, so have order if more than 1 implementation
            ReferenceMapping refMapping = (ReferenceMapping) keyMapping;
            if (refMapping.getJavaTypeMapping().length > 1) {
                orderRequired = true;
            }
        } else if (!(keyMapping instanceof PersistableMapping)) {
            // Non-PC, so depends if the key column can be used as part of a PK
            // TODO This assumes the keyMapping has a single column but what if it is Color with 4 cols?
            Column elementCol = keyMapping.getDatastoreMapping(0).getColumn();
            if (!storeMgr.getDatastoreAdapter().isValidPrimaryKeyType(elementCol.getJdbcType())) {
                // Not possible to use this Non-PC type as part of the PK
                orderRequired = true;
            }
        }
    }
    if (orderRequired) {
        // Order/Adapter (index) column is required (integer based)
        ColumnMetaData orderColmd = null;
        if (mmd.getOrderMetaData() != null && mmd.getOrderMetaData().getColumnMetaData() != null && mmd.getOrderMetaData().getColumnMetaData().length > 0) {
            // Specified "order" column info
            orderColmd = mmd.getOrderMetaData().getColumnMetaData()[0];
            if (orderColmd.getName() == null) {
                // No column name so use default
                orderColmd = new ColumnMetaData(orderColmd);
                DatastoreIdentifier id = storeMgr.getIdentifierFactory().newIndexFieldIdentifier(mmd);
                orderColmd.setName(id.getName());
            }
        } else {
            // No column name so use default
            DatastoreIdentifier id = storeMgr.getIdentifierFactory().newIndexFieldIdentifier(mmd);
            orderColmd = new ColumnMetaData();
            orderColmd.setName(id.getName());
        }
        // JDO2 spec [18.5] order column is assumed to be "int"
        orderMapping = storeMgr.getMappingManager().getMapping(int.class);
        ColumnCreator.createIndexColumn(orderMapping, storeMgr, clr, this, orderColmd, pkRequired && !pkColsSpecified);
        if (NucleusLogger.DATASTORE.isDebugEnabled()) {
            logMapping(mmd.getFullFieldName() + ".[ORDER]", orderMapping);
        }
    }
    // Define primary key of the join table (if any)
    if (pkRequired) {
        if (pkColsSpecified) {
            // Apply the users PK specification
            applyUserPrimaryKeySpecification(pkmd);
        } else {
            // Define PK using internal rules
            if (orderRequired) {
                // Order column specified so owner+order are the PK
                orderMapping.getDatastoreMapping(0).getColumn().setPrimaryKey();
            } else {
                // No order column specified so owner+key are the PK
                for (int i = 0; i < keyMapping.getNumberOfDatastoreMappings(); i++) {
                    keyMapping.getDatastoreMapping(i).getColumn().setPrimaryKey();
                }
            }
        }
    }
    if (NucleusLogger.DATASTORE_SCHEMA.isDebugEnabled()) {
        NucleusLogger.DATASTORE_SCHEMA.debug(Localiser.msg("057023", this));
    }
    storeMgr.registerTableInitialized(this);
    state = TABLE_STATE_INITIALIZED;
}
Also used : KeyMetaData(org.datanucleus.metadata.KeyMetaData) PrimaryKeyMetaData(org.datanucleus.metadata.PrimaryKeyMetaData) ForeignKeyMetaData(org.datanucleus.metadata.ForeignKeyMetaData) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) EmbeddedValuePCMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedValuePCMapping) MapMetaData(org.datanucleus.metadata.MapMetaData) PrimaryKeyMetaData(org.datanucleus.metadata.PrimaryKeyMetaData) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) DatastoreIdentifier(org.datanucleus.store.rdbms.identifier.DatastoreIdentifier) ValueMetaData(org.datanucleus.metadata.ValueMetaData) ColumnMetaData(org.datanucleus.metadata.ColumnMetaData) EmbeddedKeyPCMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedKeyPCMapping)

Example 18 with PersistableMapping

use of org.datanucleus.store.rdbms.mapping.java.PersistableMapping in project datanucleus-rdbms by datanucleus.

the class SecondaryTable method getIdMapping.

/**
 * Accessor for the ID mapping for this table.
 * @return The ID mapping
 */
public JavaTypeMapping getIdMapping() {
    if (idMapping != null) {
        return idMapping;
    }
    PersistableMapping mapping = new PersistableMapping();
    mapping.initialize(getStoreManager(), primaryTable.getClassMetaData().getFullClassName());
    if (getIdentityType() == IdentityType.DATASTORE) {
        mapping.addJavaTypeMapping(datastoreIdMapping);
    } else if (getIdentityType() == IdentityType.APPLICATION) {
        for (int i = 0; i < pkMappings.length; i++) {
            mapping.addJavaTypeMapping(pkMappings[i]);
        }
    }
    idMapping = mapping;
    return mapping;
}
Also used : PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping)

Example 19 with PersistableMapping

use of org.datanucleus.store.rdbms.mapping.java.PersistableMapping in project datanucleus-rdbms by datanucleus.

the class ClassTable method runCallBacks.

/**
 * Execute the callbacks for the classes that this table maps to.
 * @param clr ClassLoader resolver
 */
private void runCallBacks(ClassLoaderResolver clr) {
    // Run callbacks for all classes managed by this table
    Iterator<AbstractClassMetaData> cmdIter = managedClassMetaData.iterator();
    while (cmdIter.hasNext()) {
        AbstractClassMetaData managedCmd = cmdIter.next();
        if (managingClassCurrent != null && managingClassCurrent.equals(managedCmd.getFullClassName())) {
            // We can't run callbacks for this class since it is still being initialised. Mark callbacks to run after it completes
            runCallbacksAfterManageClass = true;
            break;
        }
        Collection processedCallbacks = callbacksAppliedForManagedClass.get(managedCmd.getFullClassName());
        Collection c = (Collection) storeMgr.getSchemaCallbacks().get(managedCmd.getFullClassName());
        if (c != null) {
            if (processedCallbacks == null) {
                processedCallbacks = new HashSet();
                callbacksAppliedForManagedClass.put(managedCmd.getFullClassName(), processedCallbacks);
            }
            for (Iterator it = c.iterator(); it.hasNext(); ) {
                AbstractMemberMetaData callbackMmd = (AbstractMemberMetaData) it.next();
                if (processedCallbacks.contains(callbackMmd)) {
                    continue;
                }
                processedCallbacks.add(callbackMmd);
                if (callbackMmd.getJoinMetaData() == null) {
                    // 1-N FK relationship
                    AbstractMemberMetaData ownerFmd = callbackMmd;
                    if (ownerFmd.getMappedBy() != null) {
                        // Bidirectional (element has a PC mapping to the owner)
                        // Check that the "mapped-by" field in the other class actually exists
                        AbstractMemberMetaData fmd = null;
                        if (ownerFmd.getMappedBy().indexOf('.') > 0) {
                            // TODO Can we just use getRelatedMemberMetaData always?
                            AbstractMemberMetaData[] relMmds = ownerFmd.getRelatedMemberMetaData(clr);
                            fmd = (relMmds != null && relMmds.length > 0) ? relMmds[0] : null;
                        } else {
                            fmd = managedCmd.getMetaDataForMember(ownerFmd.getMappedBy());
                        }
                        if (fmd == null) {
                            throw new NucleusUserException(Localiser.msg("057036", ownerFmd.getMappedBy(), managedCmd.getFullClassName(), ownerFmd.getFullFieldName()));
                        }
                        if (ownerFmd.getMap() != null && storeMgr.getBooleanProperty(RDBMSPropertyNames.PROPERTY_RDBMS_UNIQUE_CONSTRAINTS_MAP_INVERSE)) {
                            initializeFKMapUniqueConstraints(ownerFmd);
                        }
                        boolean duplicate = false;
                        JavaTypeMapping fkDiscrimMapping = null;
                        JavaTypeMapping orderMapping = null;
                        if (ownerFmd.hasExtension(MetaData.EXTENSION_MEMBER_RELATION_DISCRIM_COLUMN)) {
                            // Collection has a relation discriminator so we need to share the FK. Check for the required discriminator
                            String colName = ownerFmd.getValueForExtension(MetaData.EXTENSION_MEMBER_RELATION_DISCRIM_COLUMN);
                            if (colName == null) {
                                // No column defined so use a fallback name
                                colName = "RELATION_DISCRIM";
                            }
                            Set fkDiscrimEntries = getExternalFkDiscriminatorMappings().entrySet();
                            Iterator discrimMappingIter = fkDiscrimEntries.iterator();
                            while (discrimMappingIter.hasNext()) {
                                Map.Entry entry = (Map.Entry) discrimMappingIter.next();
                                JavaTypeMapping discrimMapping = (JavaTypeMapping) entry.getValue();
                                String discrimColName = (discrimMapping.getDatastoreMapping(0).getColumn().getColumnMetaData()).getName();
                                if (discrimColName.equalsIgnoreCase(colName)) {
                                    duplicate = true;
                                    fkDiscrimMapping = discrimMapping;
                                    orderMapping = getExternalOrderMappings().get(entry.getKey());
                                    break;
                                }
                            }
                            if (!duplicate) {
                                // Create the relation discriminator column since we dont have this discriminator
                                ColumnMetaData colmd = new ColumnMetaData();
                                colmd.setName(colName);
                                // Allow for elements not in any discriminated collection
                                colmd.setAllowsNull(Boolean.TRUE);
                                // Only support String discriminators currently
                                fkDiscrimMapping = storeMgr.getMappingManager().getMapping(String.class);
                                fkDiscrimMapping.setTable(this);
                                ColumnCreator.createIndexColumn(fkDiscrimMapping, storeMgr, clr, this, colmd, false);
                            }
                            if (fkDiscrimMapping != null) {
                                getExternalFkDiscriminatorMappings().put(ownerFmd, fkDiscrimMapping);
                            }
                        }
                        // Add the order mapping as necessary
                        addOrderMapping(ownerFmd, orderMapping, clr);
                    } else {
                        // Unidirectional (element knows nothing about the owner)
                        String ownerClassName = ownerFmd.getAbstractClassMetaData().getFullClassName();
                        JavaTypeMapping fkMapping = new PersistableMapping();
                        fkMapping.setTable(this);
                        fkMapping.initialize(storeMgr, ownerClassName);
                        JavaTypeMapping fkDiscrimMapping = null;
                        JavaTypeMapping orderMapping = null;
                        boolean duplicate = false;
                        try {
                            // Get the owner id mapping of the "1" end
                            DatastoreClass ownerTbl = storeMgr.getDatastoreClass(ownerClassName, clr);
                            if (ownerTbl == null) {
                                // Class doesn't have its own table (subclass-table) so find where it persists
                                AbstractClassMetaData[] ownerParentCmds = storeMgr.getClassesManagingTableForClass(ownerFmd.getAbstractClassMetaData(), clr);
                                if (ownerParentCmds.length > 1) {
                                    throw new NucleusUserException("Relation (" + ownerFmd.getFullFieldName() + ") with multiple related tables (using subclass-table). Not supported");
                                }
                                ownerClassName = ownerParentCmds[0].getFullClassName();
                                ownerTbl = storeMgr.getDatastoreClass(ownerClassName, clr);
                                if (ownerTbl == null) {
                                    throw new NucleusException("Failed to get owner table at other end of relation for field=" + ownerFmd.getFullFieldName());
                                }
                            }
                            JavaTypeMapping ownerIdMapping = ownerTbl.getIdMapping();
                            ColumnMetaDataContainer colmdContainer = null;
                            if (ownerFmd.hasCollection() || ownerFmd.hasArray()) {
                                // 1-N Collection/array
                                colmdContainer = ownerFmd.getElementMetaData();
                            } else if (ownerFmd.hasMap() && ownerFmd.getKeyMetaData() != null && ownerFmd.getKeyMetaData().getMappedBy() != null) {
                                // 1-N Map with key stored in the value
                                colmdContainer = ownerFmd.getValueMetaData();
                            } else if (ownerFmd.hasMap() && ownerFmd.getValueMetaData() != null && ownerFmd.getValueMetaData().getMappedBy() != null) {
                                // 1-N Map with value stored in the key
                                colmdContainer = ownerFmd.getKeyMetaData();
                            }
                            CorrespondentColumnsMapper correspondentColumnsMapping = new CorrespondentColumnsMapper(colmdContainer, this, ownerIdMapping, true);
                            int countIdFields = ownerIdMapping.getNumberOfDatastoreMappings();
                            for (int i = 0; i < countIdFields; i++) {
                                DatastoreMapping refDatastoreMapping = ownerIdMapping.getDatastoreMapping(i);
                                JavaTypeMapping mapping = storeMgr.getMappingManager().getMapping(refDatastoreMapping.getJavaTypeMapping().getJavaType());
                                ColumnMetaData colmd = correspondentColumnsMapping.getColumnMetaDataByIdentifier(refDatastoreMapping.getColumn().getIdentifier());
                                if (colmd == null) {
                                    throw new NucleusUserException(Localiser.msg("057035", refDatastoreMapping.getColumn().getIdentifier(), toString())).setFatal();
                                }
                                DatastoreIdentifier identifier = null;
                                IdentifierFactory idFactory = storeMgr.getIdentifierFactory();
                                if (colmd.getName() == null || colmd.getName().length() < 1) {
                                    // No user provided name so generate one
                                    identifier = idFactory.newForeignKeyFieldIdentifier(ownerFmd, null, refDatastoreMapping.getColumn().getIdentifier(), storeMgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(mapping.getJavaType()), FieldRole.ROLE_OWNER);
                                } else {
                                    // User-defined name
                                    identifier = idFactory.newColumnIdentifier(colmd.getName());
                                }
                                Column refColumn = addColumn(mapping.getJavaType().getName(), identifier, mapping, colmd);
                                refDatastoreMapping.getColumn().copyConfigurationTo(refColumn);
                                if ((colmd.getAllowsNull() == null) || (colmd.getAllowsNull() != null && colmd.isAllowsNull())) {
                                    // User either wants it nullable, or haven't specified anything, so make it nullable
                                    refColumn.setNullable(true);
                                }
                                fkMapping.addDatastoreMapping(getStoreManager().getMappingManager().createDatastoreMapping(mapping, refColumn, refDatastoreMapping.getJavaTypeMapping().getJavaType().getName()));
                                ((PersistableMapping) fkMapping).addJavaTypeMapping(mapping);
                            }
                        } catch (DuplicateColumnException dce) {
                            // If the user hasnt specified "relation-discriminator-column" here we dont allow the sharing of columns
                            if (!ownerFmd.hasExtension(MetaData.EXTENSION_MEMBER_RELATION_DISCRIM_COLUMN)) {
                                throw dce;
                            }
                            // Find the FK using this column and use it instead of creating a new one since we're sharing
                            Iterator fkIter = getExternalFkMappings().entrySet().iterator();
                            fkMapping = null;
                            while (fkIter.hasNext()) {
                                Map.Entry entry = (Map.Entry) fkIter.next();
                                JavaTypeMapping existingFkMapping = (JavaTypeMapping) entry.getValue();
                                for (int j = 0; j < existingFkMapping.getNumberOfDatastoreMappings(); j++) {
                                    if (existingFkMapping.getDatastoreMapping(j).getColumn().getIdentifier().toString().equals(dce.getConflictingColumn().getIdentifier().toString())) {
                                        // The FK is shared (and so if it is a List we also share the index)
                                        fkMapping = existingFkMapping;
                                        fkDiscrimMapping = externalFkDiscriminatorMappings.get(entry.getKey());
                                        orderMapping = getExternalOrderMappings().get(entry.getKey());
                                        break;
                                    }
                                }
                            }
                            if (fkMapping == null) {
                                // Should never happen since we know there is a col duplicating ours
                                throw dce;
                            }
                            duplicate = true;
                        }
                        if (!duplicate && ownerFmd.hasExtension(MetaData.EXTENSION_MEMBER_RELATION_DISCRIM_COLUMN)) {
                            // Create the relation discriminator column
                            String colName = ownerFmd.getValueForExtension(MetaData.EXTENSION_MEMBER_RELATION_DISCRIM_COLUMN);
                            if (colName == null) {
                                // No column defined so use a fallback name
                                colName = "RELATION_DISCRIM";
                            }
                            ColumnMetaData colmd = new ColumnMetaData();
                            colmd.setName(colName);
                            // Allow for elements not in any discriminated collection
                            colmd.setAllowsNull(Boolean.TRUE);
                            // Only support String discriminators currently
                            fkDiscrimMapping = storeMgr.getMappingManager().getMapping(String.class);
                            fkDiscrimMapping.setTable(this);
                            ColumnCreator.createIndexColumn(fkDiscrimMapping, storeMgr, clr, this, colmd, false);
                        }
                        // Save the external FK
                        getExternalFkMappings().put(ownerFmd, fkMapping);
                        if (fkDiscrimMapping != null) {
                            getExternalFkDiscriminatorMappings().put(ownerFmd, fkDiscrimMapping);
                        }
                        // Add the order mapping as necessary
                        addOrderMapping(ownerFmd, orderMapping, clr);
                    }
                }
            }
        }
    }
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) DuplicateColumnException(org.datanucleus.store.rdbms.exceptions.DuplicateColumnException) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) MacroString(org.datanucleus.util.MacroString) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) ColumnMetaDataContainer(org.datanucleus.metadata.ColumnMetaDataContainer) Iterator(java.util.Iterator) ColumnMetaData(org.datanucleus.metadata.ColumnMetaData) HashSet(java.util.HashSet) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) IdentifierFactory(org.datanucleus.store.rdbms.identifier.IdentifierFactory) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) DatastoreMapping(org.datanucleus.store.rdbms.mapping.datastore.DatastoreMapping) DatastoreIdentifier(org.datanucleus.store.rdbms.identifier.DatastoreIdentifier) Collection(java.util.Collection) NucleusException(org.datanucleus.exceptions.NucleusException) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) Map(java.util.Map) HashMap(java.util.HashMap) CorrespondentColumnsMapper(org.datanucleus.store.rdbms.mapping.CorrespondentColumnsMapper)

Example 20 with PersistableMapping

use of org.datanucleus.store.rdbms.mapping.java.PersistableMapping in project datanucleus-rdbms by datanucleus.

the class ClassTable method getExpectedForeignKeys.

/**
 * Accessor for the expected foreign keys for this table.
 * @param clr The ClassLoaderResolver
 * @return The expected foreign keys.
 */
public List<ForeignKey> getExpectedForeignKeys(ClassLoaderResolver clr) {
    assertIsInitialized();
    // Auto mode allows us to decide which FKs are needed as well as using what is in the users MetaData.
    boolean autoMode = false;
    if (storeMgr.getStringProperty(RDBMSPropertyNames.PROPERTY_RDBMS_CONSTRAINT_CREATE_MODE).equals("DataNucleus")) {
        autoMode = true;
    }
    ArrayList<ForeignKey> foreignKeys = new ArrayList<>();
    // Check each field for FK requirements (user-defined, or required)
    // <field><foreign-key>...</foreign-key></field>
    Set memberNumbersSet = memberMappingsMap.keySet();
    Iterator iter = memberNumbersSet.iterator();
    while (iter.hasNext()) {
        AbstractMemberMetaData mmd = (AbstractMemberMetaData) iter.next();
        JavaTypeMapping memberMapping = memberMappingsMap.get(mmd);
        if (memberMapping instanceof EmbeddedPCMapping) {
            EmbeddedPCMapping embMapping = (EmbeddedPCMapping) memberMapping;
            addExpectedForeignKeysForEmbeddedPCField(foreignKeys, autoMode, clr, embMapping);
        } else {
            if (ClassUtils.isReferenceType(mmd.getType()) && memberMapping instanceof ReferenceMapping) {
                // Field is a reference type, so add a FK to the table of the PC for each PC implementation
                Collection fks = TableUtils.getForeignKeysForReferenceField(memberMapping, mmd, autoMode, storeMgr, clr);
                foreignKeys.addAll(fks);
            } else if (storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(mmd.getType(), clr) != null && memberMapping.getNumberOfDatastoreMappings() > 0 && memberMapping instanceof PersistableMapping) {
                // Field is for a PC class with the FK at this side, so add a FK to the table of this PC
                ForeignKey fk = TableUtils.getForeignKeyForPCField(memberMapping, mmd, autoMode, storeMgr, clr);
                if (fk != null) {
                    // Check for dups (can happen if we override a persistent property for 1-1/N-1 in a subclass)
                    boolean exists = false;
                    for (ForeignKey theFK : foreignKeys) {
                        if (theFK.isEqual(fk)) {
                            exists = true;
                            break;
                        }
                    }
                    if (!exists) {
                        foreignKeys.add(fk);
                    }
                }
            }
        }
    }
    // FK from id column(s) to id column(s) of superclass, as specified by
    // <inheritance><join><foreign-key ...></join></inheritance>
    ForeignKeyMetaData idFkmd = (cmd.getInheritanceMetaData().getJoinMetaData() != null) ? cmd.getInheritanceMetaData().getJoinMetaData().getForeignKeyMetaData() : null;
    if (supertable != null && (autoMode || (idFkmd != null && idFkmd.getDeleteAction() != ForeignKeyAction.NONE))) {
        ForeignKey fk = new ForeignKey(getIdMapping(), dba, supertable, false);
        if (idFkmd != null && idFkmd.getName() != null) {
            fk.setName(idFkmd.getName());
        }
        foreignKeys.add(0, fk);
    }
    // Add any user-required FKs for the class as a whole
    // <class><foreign-key>...</foreign-key></field>
    Iterator<AbstractClassMetaData> cmdIter = managedClassMetaData.iterator();
    while (cmdIter.hasNext()) {
        AbstractClassMetaData thisCmd = cmdIter.next();
        List<ForeignKeyMetaData> fkmds = thisCmd.getForeignKeyMetaData();
        if (fkmds != null) {
            for (ForeignKeyMetaData fkmd : fkmds) {
                ForeignKey fk = getForeignKeyForForeignKeyMetaData(fkmd);
                if (fk != null) {
                    foreignKeys.add(fk);
                }
            }
        }
    }
    Map externalFks = getExternalFkMappings();
    if (!externalFks.isEmpty()) {
        // 1-N FK relationships - FK to id column(s) of owner table where this is the element table and we have a FK
        Collection externalFkKeys = externalFks.entrySet();
        Iterator<Map.Entry<AbstractMemberMetaData, JavaTypeMapping>> externalFkKeysIter = externalFkKeys.iterator();
        while (externalFkKeysIter.hasNext()) {
            Map.Entry<AbstractMemberMetaData, JavaTypeMapping> entry = externalFkKeysIter.next();
            AbstractMemberMetaData fmd = entry.getKey();
            DatastoreClass referencedTable = storeMgr.getDatastoreClass(fmd.getAbstractClassMetaData().getFullClassName(), clr);
            if (referencedTable != null) {
                // Take <foreign-key> from either <field> or <element>
                ForeignKeyMetaData fkmd = fmd.getForeignKeyMetaData();
                if (fkmd == null && fmd.getElementMetaData() != null) {
                    fkmd = fmd.getElementMetaData().getForeignKeyMetaData();
                }
                if ((fkmd != null && fkmd.getDeleteAction() != ForeignKeyAction.NONE) || autoMode) {
                    // Either has been specified by user, or using autoMode, so add FK
                    JavaTypeMapping fkMapping = entry.getValue();
                    ForeignKey fk = new ForeignKey(fkMapping, dba, referencedTable, true);
                    // Does nothing when no FK MetaData
                    fk.setForMetaData(fkmd);
                    if (!foreignKeys.contains(fk)) {
                        // Only add when not already present (in the case of shared FKs there can be dups here)
                        foreignKeys.add(fk);
                    }
                }
            }
        }
    }
    return foreignKeys;
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) EmbeddedPCMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedPCMapping) ArrayList(java.util.ArrayList) ForeignKey(org.datanucleus.store.rdbms.key.ForeignKey) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) Iterator(java.util.Iterator) Collection(java.util.Collection) ForeignKeyMetaData(org.datanucleus.metadata.ForeignKeyMetaData) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) Map(java.util.Map) HashMap(java.util.HashMap)

Aggregations

PersistableMapping (org.datanucleus.store.rdbms.mapping.java.PersistableMapping)33 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)27 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)17 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)17 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)16 ReferenceMapping (org.datanucleus.store.rdbms.mapping.java.ReferenceMapping)15 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)13 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)10 Collection (java.util.Collection)7 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)7 ArrayList (java.util.ArrayList)6 HashSet (java.util.HashSet)6 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)6 HashMap (java.util.HashMap)5 Iterator (java.util.Iterator)5 List (java.util.List)5 Map (java.util.Map)5 NucleusException (org.datanucleus.exceptions.NucleusException)5 SQLTable (org.datanucleus.store.rdbms.sql.SQLTable)5 FetchPlanForClass (org.datanucleus.FetchPlanForClass)4