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