Search in sources :

Example 51 with AbstractMemberMetaData

use of org.datanucleus.metadata.AbstractMemberMetaData in project datanucleus-rdbms by datanucleus.

the class ClassTable method initializeFKMapUniqueConstraints.

/**
 * Method to initialise unique constraints for 1-N Map using FK.
 * @param ownerMmd metadata for the field/property with the map in the owner class
 */
private void initializeFKMapUniqueConstraints(AbstractMemberMetaData ownerMmd) {
    // Load "mapped-by"
    AbstractMemberMetaData mfmd = null;
    // Field in our class that maps back to the owner class
    String map_field_name = ownerMmd.getMappedBy();
    if (map_field_name != null) {
        // Bidirectional
        mfmd = cmd.getMetaDataForMember(map_field_name);
        if (mfmd == null) {
            // Field not in primary class so may be in subclass so check all managed classes
            Iterator<AbstractClassMetaData> cmdIter = managedClassMetaData.iterator();
            while (cmdIter.hasNext()) {
                AbstractClassMetaData managedCmd = cmdIter.next();
                mfmd = managedCmd.getMetaDataForMember(map_field_name);
                if (mfmd != null) {
                    break;
                }
            }
        }
        if (mfmd == null) {
            // "mapped-by" refers to a field in our class that doesnt exist!
            throw new NucleusUserException(Localiser.msg("057036", map_field_name, cmd.getFullClassName(), ownerMmd.getFullFieldName()));
        }
        if (ownerMmd.getJoinMetaData() == null) {
            // Load field of key in value
            if (ownerMmd.getKeyMetaData() != null && ownerMmd.getKeyMetaData().getMappedBy() != null) {
                // Key field is stored in the value table
                AbstractMemberMetaData kmd = null;
                String key_field_name = ownerMmd.getKeyMetaData().getMappedBy();
                if (key_field_name != null) {
                    kmd = cmd.getMetaDataForMember(key_field_name);
                }
                if (kmd == null) {
                    // Field not in primary class so may be in subclass so check all managed classes
                    Iterator<AbstractClassMetaData> cmdIter = managedClassMetaData.iterator();
                    while (cmdIter.hasNext()) {
                        AbstractClassMetaData managedCmd = cmdIter.next();
                        kmd = managedCmd.getMetaDataForMember(key_field_name);
                        if (kmd != null) {
                            break;
                        }
                    }
                }
                if (kmd == null) {
                    throw new ClassDefinitionException(Localiser.msg("057007", mfmd.getFullFieldName(), key_field_name));
                }
                JavaTypeMapping ownerMapping = getMemberMapping(map_field_name);
                JavaTypeMapping keyMapping = getMemberMapping(kmd.getName());
                if (dba.supportsOption(DatastoreAdapter.NULLS_IN_CANDIDATE_KEYS) || (!ownerMapping.isNullable() && !keyMapping.isNullable())) {
                    // cannot do this so just omit it.
                    if (keyMapping.getTable() == this && ownerMapping.getTable() == this) {
                        CandidateKey ck = new CandidateKey(this, null);
                        // This HashSet is to avoid duplicate adding of columns.
                        HashSet addedColumns = new HashSet();
                        // Add columns for the owner field
                        int countOwnerFields = ownerMapping.getNumberOfDatastoreMappings();
                        for (int i = 0; i < countOwnerFields; i++) {
                            Column col = ownerMapping.getDatastoreMapping(i).getColumn();
                            addedColumns.add(col);
                            ck.addColumn(col);
                        }
                        // Add columns for the key field
                        int countKeyFields = keyMapping.getNumberOfDatastoreMappings();
                        for (int i = 0; i < countKeyFields; i++) {
                            Column col = keyMapping.getDatastoreMapping(i).getColumn();
                            if (!addedColumns.contains(col)) {
                                addedColumns.add(col);
                                ck.addColumn(col);
                            } else {
                                NucleusLogger.DATASTORE_SCHEMA.warn(Localiser.msg("057041", ownerMmd.getName()));
                            }
                        }
                        if (candidateKeysByMapField.put(mfmd, ck) != null) {
                            // We have multiple "mapped-by" coming to this field so give a warning that this may potentially
                            // cause problems. For example if they have the key field defined here for 2 different relations
                            // so you may get keys/values appearing in the other relation that shouldn't be.
                            // Logged as a WARNING for now.
                            // If there is a situation where this should throw an exception, please update this AND COMMENT WHY.
                            NucleusLogger.DATASTORE_SCHEMA.warn(Localiser.msg("057012", mfmd.getFullFieldName(), ownerMmd.getFullFieldName()));
                        }
                    }
                }
            } else if (ownerMmd.getValueMetaData() != null && ownerMmd.getValueMetaData().getMappedBy() != null) {
                // Value field is stored in the key table
                AbstractMemberMetaData vmd = null;
                String value_field_name = ownerMmd.getValueMetaData().getMappedBy();
                if (value_field_name != null) {
                    vmd = cmd.getMetaDataForMember(value_field_name);
                }
                if (vmd == null) {
                    throw new ClassDefinitionException(Localiser.msg("057008", mfmd));
                }
                JavaTypeMapping ownerMapping = getMemberMapping(map_field_name);
                JavaTypeMapping valueMapping = getMemberMapping(vmd.getName());
                if (dba.supportsOption(DatastoreAdapter.NULLS_IN_CANDIDATE_KEYS) || (!ownerMapping.isNullable() && !valueMapping.isNullable())) {
                    // cannot do this so just omit it.
                    if (valueMapping.getTable() == this && ownerMapping.getTable() == this) {
                        CandidateKey ck = new CandidateKey(this, null);
                        // This HashSet is to avoid duplicate adding of columns.
                        Set<Column> addedColumns = new HashSet<>();
                        // Add columns for the owner field
                        int countOwnerFields = ownerMapping.getNumberOfDatastoreMappings();
                        for (int i = 0; i < countOwnerFields; i++) {
                            Column col = ownerMapping.getDatastoreMapping(i).getColumn();
                            addedColumns.add(col);
                            ck.addColumn(col);
                        }
                        // Add columns for the value field
                        int countValueFields = valueMapping.getNumberOfDatastoreMappings();
                        for (int i = 0; i < countValueFields; i++) {
                            Column col = valueMapping.getDatastoreMapping(i).getColumn();
                            if (!addedColumns.contains(col)) {
                                addedColumns.add(col);
                                ck.addColumn(col);
                            } else {
                                NucleusLogger.DATASTORE_SCHEMA.warn(Localiser.msg("057042", ownerMmd.getName()));
                            }
                        }
                        if (candidateKeysByMapField.put(mfmd, ck) != null) {
                            // We have multiple "mapped-by" coming to this field so give a warning that this may potentially
                            // cause problems. For example if they have the key field defined here for 2 different relations
                            // so you may get keys/values appearing in the other relation that shouldn't be.
                            // Logged as a WARNING for now.
                            // If there is a situation where this should throw an exception, please update this AND COMMENT WHY.
                            NucleusLogger.DATASTORE_SCHEMA.warn(Localiser.msg("057012", mfmd.getFullFieldName(), ownerMmd.getFullFieldName()));
                        }
                    }
                }
            } else {
                // We can only have either the key stored in the value or the value stored in the key but nothing else!
                throw new ClassDefinitionException(Localiser.msg("057009", ownerMmd.getFullFieldName()));
            }
        }
    }
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) MacroString(org.datanucleus.util.MacroString) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) CandidateKey(org.datanucleus.store.rdbms.key.CandidateKey) ClassDefinitionException(org.datanucleus.store.rdbms.exceptions.ClassDefinitionException) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) HashSet(java.util.HashSet)

Example 52 with AbstractMemberMetaData

use of org.datanucleus.metadata.AbstractMemberMetaData in project datanucleus-rdbms by datanucleus.

the class ElementContainerTable method getExpectedForeignKeys.

/**
 * Accessor for the expected foreign keys for this table.
 * @param clr The ClassLoaderResolver
 * @return The expected foreign keys.
 */
public List getExpectedForeignKeys(ClassLoaderResolver clr) {
    assertIsInitialized();
    // Find the mode that we're operating in for FK addition
    boolean autoMode = false;
    if (storeMgr.getStringProperty(RDBMSPropertyNames.PROPERTY_RDBMS_CONSTRAINT_CREATE_MODE).equals("DataNucleus")) {
        autoMode = true;
    }
    ArrayList foreignKeys = new ArrayList();
    try {
        // FK from join table to owner table
        DatastoreClass referencedTable = storeMgr.getDatastoreClass(ownerType, clr);
        if (referencedTable != null) {
            // Single owner table, so add a single FK to the owner as appropriate
            ForeignKey fk = getForeignKeyToOwner(referencedTable, autoMode);
            if (fk != null) {
                foreignKeys.add(fk);
            }
        } else {
        // No single owner so we don't bother with the FK since referential integrity by FK cannot work
        // if we don't have a single owner at the other end of the FK(s).
        }
        // FK from join table to element table(s)
        if (elementMapping instanceof SerialisedPCMapping) {
        // Do nothing since no element table
        } else if (elementMapping instanceof EmbeddedElementPCMapping) {
            // Add any FKs for the fields of the (embedded) element
            EmbeddedElementPCMapping embMapping = (EmbeddedElementPCMapping) elementMapping;
            for (int i = 0; i < embMapping.getNumberOfJavaTypeMappings(); i++) {
                JavaTypeMapping embFieldMapping = embMapping.getJavaTypeMapping(i);
                AbstractMemberMetaData embFmd = embFieldMapping.getMemberMetaData();
                if (ClassUtils.isReferenceType(embFmd.getType()) && embFieldMapping 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(embFieldMapping, embFmd, autoMode, storeMgr, clr);
                    foreignKeys.addAll(fks);
                } else if (storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(embFmd.getType(), clr) != null && embFieldMapping.getNumberOfDatastoreMappings() > 0 && embFieldMapping 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(embFieldMapping, embFmd, autoMode, storeMgr, clr);
                    if (fk != null) {
                        foreignKeys.add(fk);
                    }
                }
            }
        } else if (elementMapping instanceof ReferenceMapping) {
            JavaTypeMapping[] implJavaTypeMappings = ((ReferenceMapping) elementMapping).getJavaTypeMapping();
            for (int i = 0; i < implJavaTypeMappings.length; i++) {
                JavaTypeMapping implMapping = implJavaTypeMappings[i];
                if (storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(implMapping.getType(), clr) != null && implMapping.getNumberOfDatastoreMappings() > 0) {
                    referencedTable = storeMgr.getDatastoreClass(implMapping.getType(), clr);
                    if (referencedTable != null) {
                        ForeignKey fk = getForeignKeyToElement(referencedTable, autoMode, implMapping);
                        if (fk != null) {
                            foreignKeys.add(fk);
                        }
                    }
                }
            }
        } else {
            referencedTable = storeMgr.getDatastoreClass(getElementType(), clr);
            if (referencedTable != null) {
                ForeignKey fk = getForeignKeyToElement(referencedTable, autoMode, elementMapping);
                if (fk != null) {
                    foreignKeys.add(fk);
                }
            } else {
            // Either no element table or multiple (where the user has element with "subclass-table" strategy, or using "complete-table")
            // so do nothing since referential integrity will not allow multiple FKs.
            }
        }
    } catch (NoTableManagedException e) {
    // expected when no table exists
    }
    return foreignKeys;
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) ArrayList(java.util.ArrayList) ForeignKey(org.datanucleus.store.rdbms.key.ForeignKey) EmbeddedElementPCMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedElementPCMapping) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) Collection(java.util.Collection) SerialisedPCMapping(org.datanucleus.store.rdbms.mapping.java.SerialisedPCMapping) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) NoTableManagedException(org.datanucleus.store.rdbms.exceptions.NoTableManagedException)

Example 53 with AbstractMemberMetaData

use of org.datanucleus.metadata.AbstractMemberMetaData in project datanucleus-rdbms by datanucleus.

the class ElementContainerTable method initialize.

/**
 * Method to initialise the table definition. Adds the owner mapping.
 * @param clr The ClassLoaderResolver
 */
public void initialize(ClassLoaderResolver clr) {
    assertIsUninitialized();
    // Add owner mapping
    AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
    ColumnMetaData[] columnMetaData = 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
        columnMetaData = mmd.getJoinMetaData().getColumnMetaData();
    } else if (relatedMmds != null && relatedMmds[0].getElementMetaData() != null && relatedMmds[0].getElementMetaData().getColumnMetaData() != null && relatedMmds[0].getElementMetaData().getColumnMetaData().length > 0) {
        // Column mappings defined at other side (M-N)
        // When specified at other side they use the <element> tag
        // ** This is really only for Collections/Sets since M-N doesnt make sense for indexed Lists/arrays **
        columnMetaData = relatedMmds[0].getElementMetaData().getColumnMetaData();
    }
    try {
        ownerMapping = ColumnCreator.createColumnsForJoinTables(clr.classForName(ownerType), mmd, columnMetaData, storeMgr, this, false, false, FieldRole.ROLE_OWNER, clr, ownerTable);
    } catch (NoTableManagedException ntme) {
        // Maybe this is a join table from an embedded object, so no table to link back to
        throw new NucleusUserException("Table " + toString() + " for member=" + mmd.getFullFieldName() + " needs a column to link back to its owner, yet the owner type (" + ownerType + ") has no table of its own (embedded?)");
    }
    if (NucleusLogger.DATASTORE.isDebugEnabled()) {
        logMapping(mmd.getFullFieldName() + ".[OWNER]", ownerMapping);
    }
    // Add any distinguisher column
    if (mmd.hasExtension(MetaData.EXTENSION_MEMBER_RELATION_DISCRIM_COLUMN) || mmd.hasExtension(MetaData.EXTENSION_MEMBER_RELATION_DISCRIM_VALUE)) {
        // Generate some columnMetaData for our new column
        String colName = mmd.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);
        boolean relationDiscriminatorPk = false;
        if (mmd.hasExtension(MetaData.EXTENSION_MEMBER_RELATION_DISCRIM_PK) && mmd.getValueForExtension(MetaData.EXTENSION_MEMBER_RELATION_DISCRIM_PK).equalsIgnoreCase("true")) {
            // Default this to not be part of the PK of the join table, but allow the user to override it
            relationDiscriminatorPk = true;
        }
        if (!relationDiscriminatorPk) {
            // Allow for elements not in any discriminated collection (when not PK)
            colmd.setAllowsNull(Boolean.TRUE);
        }
        // Create the mapping and its datastore column (only support String relation discriminators here)
        relationDiscriminatorMapping = storeMgr.getMappingManager().getMapping(String.class);
        ColumnCreator.createIndexColumn(relationDiscriminatorMapping, storeMgr, clr, this, colmd, relationDiscriminatorPk);
        relationDiscriminatorValue = mmd.getValueForExtension(MetaData.EXTENSION_MEMBER_RELATION_DISCRIM_VALUE);
        if (relationDiscriminatorValue == null) {
            // No value defined so just use the field name
            relationDiscriminatorValue = mmd.getFullFieldName();
        }
    }
}
Also used : NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ColumnMetaData(org.datanucleus.metadata.ColumnMetaData) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) NoTableManagedException(org.datanucleus.store.rdbms.exceptions.NoTableManagedException)

Example 54 with AbstractMemberMetaData

use of org.datanucleus.metadata.AbstractMemberMetaData in project datanucleus-rdbms by datanucleus.

the class SecondaryTable method providePrimaryKeyMappings.

/**
 * Provide the mappings to the consumer for all primary-key fields mapped to this table (for application identity).
 * @param consumer Consumer for the mappings
 */
public void providePrimaryKeyMappings(MappingConsumer consumer) {
    consumer.preConsumeMapping(highestMemberNumber + 1);
    ClassMetaData cmd = primaryTable.getClassMetaData();
    if (pkMappings != null) {
        // Application identity
        int[] primaryKeyFieldNumbers = cmd.getPKMemberPositions();
        for (int i = 0; i < pkMappings.length; i++) {
            // Make the assumption that the pkMappings are in the same order as the absolute field numbers
            AbstractMemberMetaData fmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(primaryKeyFieldNumbers[i]);
            consumer.consumeMapping(pkMappings[i], fmd);
        }
    } else {
        // Datastore identity
        int[] primaryKeyFieldNumbers = cmd.getPKMemberPositions();
        int countPkFields = cmd.getNoOfPrimaryKeyMembers();
        for (int i = 0; i < countPkFields; i++) {
            AbstractMemberMetaData pkfmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(primaryKeyFieldNumbers[i]);
            consumer.consumeMapping(getMemberMapping(pkfmd), pkfmd);
        }
    }
}
Also used : AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) ClassMetaData(org.datanucleus.metadata.ClassMetaData)

Example 55 with AbstractMemberMetaData

use of org.datanucleus.metadata.AbstractMemberMetaData in project datanucleus-rdbms by datanucleus.

the class AbstractClassTable method addMemberMapping.

/**
 * Utility to add the mapping for a field/property to the managed list.
 * @param fieldMapping The mapping for the field/property
 */
protected void addMemberMapping(JavaTypeMapping fieldMapping) {
    AbstractMemberMetaData mmd = fieldMapping.getMemberMetaData();
    logMapping(mmd.getFullFieldName(), fieldMapping);
    memberMappingsMap.put(mmd, fieldMapping);
    // Update highest field number if this is higher
    int absoluteFieldNumber = mmd.getAbsoluteFieldNumber();
    if (absoluteFieldNumber > highestMemberNumber) {
        highestMemberNumber = absoluteFieldNumber;
    }
}
Also used : AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Aggregations

AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)267 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)89 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)84 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)82 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)59 ClassMetaData (org.datanucleus.metadata.ClassMetaData)55 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)50 NucleusException (org.datanucleus.exceptions.NucleusException)41 MetaDataManager (org.datanucleus.metadata.MetaDataManager)40 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)38 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)35 RelationType (org.datanucleus.metadata.RelationType)33 NucleusContext (org.datanucleus.NucleusContext)32 PersistenceNucleusContextImpl (org.datanucleus.PersistenceNucleusContextImpl)32 JPAMetaDataManager (org.datanucleus.api.jpa.metadata.JPAMetaDataManager)29 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)28 ColumnMetaData (org.datanucleus.metadata.ColumnMetaData)27 ExecutionContext (org.datanucleus.ExecutionContext)26 ObjectProvider (org.datanucleus.state.ObjectProvider)25 ArrayList (java.util.ArrayList)24