Search in sources :

Example 1 with ClassDefinitionException

use of org.datanucleus.store.rdbms.exceptions.ClassDefinitionException 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.getNumberOfColumnMappings();
                        for (int i = 0; i < countOwnerFields; i++) {
                            Column col = ownerMapping.getColumnMapping(i).getColumn();
                            addedColumns.add(col);
                            ck.addColumn(col);
                        }
                        // Add columns for the key field
                        int countKeyFields = keyMapping.getNumberOfColumnMappings();
                        for (int i = 0; i < countKeyFields; i++) {
                            Column col = keyMapping.getColumnMapping(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.getNumberOfColumnMappings();
                        for (int i = 0; i < countOwnerFields; i++) {
                            Column col = ownerMapping.getColumnMapping(i).getColumn();
                            addedColumns.add(col);
                            ck.addColumn(col);
                        }
                        // Add columns for the value field
                        int countValueFields = valueMapping.getNumberOfColumnMappings();
                        for (int i = 0; i < countValueFields; i++) {
                            Column col = valueMapping.getColumnMapping(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)

Aggregations

HashSet (java.util.HashSet)1 Set (java.util.Set)1 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)1 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)1 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)1 ClassDefinitionException (org.datanucleus.store.rdbms.exceptions.ClassDefinitionException)1 CandidateKey (org.datanucleus.store.rdbms.key.CandidateKey)1 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)1 MacroString (org.datanucleus.util.MacroString)1