use of org.datanucleus.metadata.AbstractClassMetaData in project datanucleus-rdbms by datanucleus.
the class ExpressionUtils method getEqualityExpressionForObjectExpressions.
/**
* Method to generate an equality/inequality expression between two ObjectExpressions.
* Either or both of the expressions can be ObjectLiterals.
* @param expr1 First expression
* @param expr2 Second expression
* @param equals Whether it is equality (otherwise inequality)
* @return The expression
*/
public static BooleanExpression getEqualityExpressionForObjectExpressions(ObjectExpression expr1, ObjectExpression expr2, boolean equals) {
SQLStatement stmt = expr1.stmt;
RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
ClassLoaderResolver clr = stmt.getClassLoaderResolver();
ApiAdapter api = storeMgr.getApiAdapter();
if (expr1 instanceof ObjectLiteral && expr2 instanceof ObjectLiteral) {
// ObjectLiterall == ObjectLiteral
ObjectLiteral lit1 = (ObjectLiteral) expr1;
ObjectLiteral lit2 = (ObjectLiteral) expr2;
return new BooleanLiteral(stmt, expr1.mapping, equals ? lit1.getValue().equals(lit2.getValue()) : !lit1.getValue().equals(lit2.getValue()));
} else if (expr1 instanceof ObjectLiteral || expr2 instanceof ObjectLiteral) {
// ObjectExpression == ObjectLiteral, ObjectLiteral == ObjectExpression
BooleanExpression bExpr = null;
boolean secondIsLiteral = (expr2 instanceof ObjectLiteral);
Object value = (!secondIsLiteral ? ((ObjectLiteral) expr1).getValue() : ((ObjectLiteral) expr2).getValue());
if (IdentityUtils.isDatastoreIdentity(value)) {
// Object is an OID
Object valueKey = IdentityUtils.getTargetKeyForDatastoreIdentity(value);
JavaTypeMapping m = storeMgr.getSQLExpressionFactory().getMappingForType(valueKey.getClass(), false);
SQLExpression oidLit = exprFactory.newLiteral(stmt, m, valueKey);
if (equals) {
return (secondIsLiteral ? expr1.subExprs.getExpression(0).eq(oidLit) : expr2.subExprs.getExpression(0).eq(oidLit));
}
return (secondIsLiteral ? expr1.subExprs.getExpression(0).ne(oidLit) : expr2.subExprs.getExpression(0).ne(oidLit));
} else if (IdentityUtils.isSingleFieldIdentity(value)) {
// Object is SingleFieldIdentity
Object valueKey = IdentityUtils.getTargetKeyForSingleFieldIdentity(value);
// This used to use ((SingleFieldId)value).getTargetClass() for some reason, which contradicts the above datastore id method
JavaTypeMapping m = storeMgr.getSQLExpressionFactory().getMappingForType(valueKey.getClass(), false);
SQLExpression oidLit = exprFactory.newLiteral(stmt, m, valueKey);
if (equals) {
return (secondIsLiteral ? expr1.subExprs.getExpression(0).eq(oidLit) : expr2.subExprs.getExpression(0).eq(oidLit));
}
return (secondIsLiteral ? expr1.subExprs.getExpression(0).ne(oidLit) : expr2.subExprs.getExpression(0).ne(oidLit));
} else {
AbstractClassMetaData cmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(value.getClass(), clr);
if (cmd != null) {
// Value is a persistable object
if (cmd.getIdentityType() == IdentityType.APPLICATION) {
// Application identity
if (api.getIdForObject(value) != null) {
// Persistent PC object (FCO)
// Cater for composite PKs and parts of PK being PC mappings, and recursion
ObjectExpression expr = (secondIsLiteral ? expr1 : expr2);
JavaTypeMapping[] pkMappingsApp = new JavaTypeMapping[expr.subExprs.size()];
Object[] pkFieldValues = new Object[expr.subExprs.size()];
int position = 0;
ExecutionContext ec = api.getExecutionContext(value);
JavaTypeMapping thisMapping = expr.mapping;
if (expr.mapping instanceof ReferenceMapping) {
// "InterfaceField == value", so pick an implementation mapping that is castable
thisMapping = null;
ReferenceMapping refMapping = (ReferenceMapping) expr.mapping;
JavaTypeMapping[] implMappings = refMapping.getJavaTypeMapping();
for (int i = 0; i < implMappings.length; i++) {
Class implType = clr.classForName(implMappings[i].getType());
if (implType.isAssignableFrom(value.getClass())) {
thisMapping = implMappings[i];
break;
}
}
}
if (thisMapping == null) {
// Just return a (1=0) since no implementation castable
return exprFactory.newLiteral(stmt, expr1.mapping, false).eq(exprFactory.newLiteral(stmt, expr1.mapping, true));
}
for (int i = 0; i < cmd.getNoOfPrimaryKeyMembers(); i++) {
AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(cmd.getPKMemberPositions()[i]);
Object fieldValue = ExpressionUtils.getValueForMemberOfObject(ec, mmd, value);
JavaTypeMapping mapping = ((PersistableMapping) thisMapping).getJavaTypeMapping()[i];
if (mapping instanceof PersistableMapping) {
position = ExpressionUtils.populatePrimaryKeyMappingsValuesForPCMapping(pkMappingsApp, pkFieldValues, position, (PersistableMapping) mapping, cmd, mmd, fieldValue, storeMgr, clr);
} else {
pkMappingsApp[position] = mapping;
pkFieldValues[position] = fieldValue;
position++;
}
}
for (int i = 0; i < expr.subExprs.size(); i++) {
SQLExpression source = expr.subExprs.getExpression(i);
SQLExpression target = exprFactory.newLiteral(stmt, pkMappingsApp[i], pkFieldValues[i]);
BooleanExpression subExpr = (secondIsLiteral ? source.eq(target) : target.eq(source));
if (bExpr == null) {
bExpr = subExpr;
} else {
bExpr = bExpr.and(subExpr);
}
}
} else {
// PC object with no id (embedded, or transient maybe)
if (secondIsLiteral) {
for (int i = 0; i < expr1.subExprs.size(); i++) {
// Query should return nothing (so just do "(1 = 0)")
NucleusLogger.QUERY.warn(Localiser.msg("037003", value));
bExpr = exprFactory.newLiteral(stmt, expr1.mapping, false).eq(exprFactory.newLiteral(stmt, expr1.mapping, true));
// It is arguable that we should compare the id with null (as below)
/*bExpr = expr.eq(new NullLiteral(qs));*/
}
} else {
for (int i = 0; i < expr2.subExprs.size(); i++) {
// Query should return nothing (so just do "(1 = 0)")
NucleusLogger.QUERY.warn(Localiser.msg("037003", value));
bExpr = exprFactory.newLiteral(stmt, expr2.mapping, false).eq(exprFactory.newLiteral(stmt, expr2.mapping, true));
// It is arguable that we should compare the id with null (as below)
/*bExpr = expr.eq(new NullLiteral(qs));*/
}
}
}
// TODO Allow for !equals
return bExpr;
} else if (cmd.getIdentityType() == IdentityType.DATASTORE) {
// Datastore identity
SQLExpression source = (secondIsLiteral ? expr1.subExprs.getExpression(0) : expr2.subExprs.getExpression(0));
JavaTypeMapping mapping = (secondIsLiteral ? expr1.mapping : expr2.mapping);
Object objectId = api.getIdForObject(value);
if (objectId == null) {
// PC object with no id (embedded, or transient maybe)
// Query should return nothing (so just do "(1 = 0)")
NucleusLogger.QUERY.warn(Localiser.msg("037003", value));
// TODO Allow for !equals
return exprFactory.newLiteral(stmt, mapping, false).eq(exprFactory.newLiteral(stmt, mapping, true));
// It is arguable that we should compare the id with null (as below)
/*bExpr = expr.eq(new NullLiteral(qs));*/
}
Object objectIdKey = IdentityUtils.getTargetKeyForDatastoreIdentity(objectId);
JavaTypeMapping m = storeMgr.getSQLExpressionFactory().getMappingForType(objectIdKey.getClass(), false);
SQLExpression oidExpr = exprFactory.newLiteral(stmt, m, objectIdKey);
if (equals) {
return source.eq(oidExpr);
}
return source.ne(oidExpr);
}
} else {
// No metadata, so we either have an application identity, or any object
String pcClassName = storeMgr.getClassNameForObjectID(value, clr, null);
if (pcClassName != null) {
// Object is an application identity
cmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(pcClassName, clr);
return (secondIsLiteral ? ExpressionUtils.getAppIdEqualityExpression(value, expr1, storeMgr, clr, cmd, null, null) : ExpressionUtils.getAppIdEqualityExpression(value, expr2, storeMgr, clr, cmd, null, null));
// TODO Allow for !equals
}
// Value not persistable nor an identity, so return nothing "(1 = 0)"
return exprFactory.newLiteral(stmt, expr1.mapping, false).eq(exprFactory.newLiteral(stmt, expr1.mapping, true));
// TODO Allow for !equals
}
}
} else {
// ObjectExpression == ObjectExpression
BooleanExpression resultExpr = null;
for (int i = 0; i < expr1.subExprs.size(); i++) {
SQLExpression sourceExpr = expr1.subExprs.getExpression(i);
SQLExpression targetExpr = expr2.subExprs.getExpression(i);
if (resultExpr == null) {
resultExpr = sourceExpr.eq(targetExpr);
} else {
resultExpr = resultExpr.and(sourceExpr.eq(targetExpr));
}
}
if (!equals) {
resultExpr = new BooleanExpression(Expression.OP_NOT, resultExpr != null ? resultExpr.encloseInParentheses() : null);
}
return resultExpr;
}
return null;
}
use of org.datanucleus.metadata.AbstractClassMetaData in project datanucleus-rdbms by datanucleus.
the class CollectionContainsMethod method containsAsSubquery.
/**
* Method to return an expression for Collection.contains using a subquery "EXISTS".
* This is for use when there are "!contains" or "OR" operations in the filter.
* Creates the following SQL,
* <ul>
* <li><b>Collection of NonPC using join table</b>
* <pre>
* SELECT 1 FROM JOIN_TBL A0_SUB
* WHERE A0_SUB.JOIN_OWN_ID = A0.ID AND A0_SUB.JOIN_ELEM_ID = {elemExpr}
* </pre>
* </li>
* <li><b>Collection of PC using join table</b>
* <pre>
* SELECT 1 FROM ELEM_TABLE A0_SUB INNER JOIN JOIN_TBL B0 ON ...
* WHERE B0.JOIN_OWN_ID = A0.ID AND A0_SUB.ID = {elemExpr}
* </pre>
* </li>
* <li><b>Collection of PC using FK</b>
* <pre>
* SELECT 1 FROM ELEM_TABLE A0_SUB
* WHERE A0_SUB.OWN_ID = A0.ID AND A0_SUB.ID = {elemExpr}
* </pre>
* </li>
* </ul>
* and returns a BooleanSubqueryExpression ("EXISTS (subquery)")
* @param stmt SQLStatement
* @param collExpr Collection expression
* @param elemExpr Expression for the element
* @return Contains expression
*/
protected SQLExpression containsAsSubquery(SQLStatement stmt, CollectionExpression collExpr, SQLExpression elemExpr) {
boolean elemIsUnbound = (elemExpr instanceof UnboundExpression);
String varName = null;
if (elemIsUnbound) {
varName = ((UnboundExpression) elemExpr).getVariableName();
NucleusLogger.QUERY.debug("collection.contains(" + elemExpr + ") binding unbound variable " + varName + " using SUBQUERY");
}
RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
AbstractMemberMetaData mmd = collExpr.getJavaTypeMapping().getMemberMetaData();
AbstractClassMetaData elemCmd = mmd.getCollection().getElementClassMetaData(clr);
CollectionTable joinTbl = (CollectionTable) storeMgr.getTable(mmd);
String elemType = mmd.getCollection().getElementType();
if (elemIsUnbound) {
Class varType = stmt.getQueryGenerator().getTypeOfVariable(varName);
if (varType != null) {
elemType = varType.getName();
elemCmd = storeMgr.getMetaDataManager().getMetaDataForClass(elemType, clr);
}
}
SelectStatement subStmt = null;
if (joinTbl != null) {
// JoinTable Collection
if (elemCmd == null) {
// Collection<Non-PC>
subStmt = new SelectStatement(stmt, storeMgr, joinTbl, null, null);
subStmt.setClassLoaderResolver(clr);
JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
// Restrict to collection owner
JavaTypeMapping ownerMapping = ((JoinTable) joinTbl).getOwnerMapping();
SQLExpression ownerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, collExpr.getSQLTable(), collExpr.getSQLTable().getTable().getIdMapping());
subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
SQLExpression elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), joinTbl.getElementMapping());
if (elemIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(varName, null, elemIdExpr.getSQLTable(), elemIdExpr.getJavaTypeMapping());
} else {
// Add restrict to element
addRestrictionOnElement(subStmt, elemIdExpr, elemExpr);
}
} else {
// Collection<PC>
DatastoreClass elemTbl = storeMgr.getDatastoreClass(elemType, clr);
subStmt = new SelectStatement(stmt, storeMgr, elemTbl, null, null);
subStmt.setClassLoaderResolver(clr);
JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
// Join to join table
SQLTable joinSqlTbl = subStmt.join(JoinType.INNER_JOIN, subStmt.getPrimaryTable(), elemTbl.getIdMapping(), joinTbl, null, joinTbl.getElementMapping(), null, null, true, null);
// Restrict to collection owner
JavaTypeMapping ownerMapping = ((JoinTable) joinTbl).getOwnerMapping();
SQLExpression ownerExpr = exprFactory.newExpression(subStmt, joinSqlTbl, ownerMapping);
SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, collExpr.getSQLTable(), collExpr.getSQLTable().getTable().getIdMapping());
subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
SQLExpression elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), elemTbl.getIdMapping());
if (elemIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(varName, elemCmd, elemIdExpr.getSQLTable(), elemIdExpr.getJavaTypeMapping());
} else {
// Add restrict to element
addRestrictionOnElement(subStmt, elemIdExpr, elemExpr);
}
}
} else {
// FK Collection
DatastoreClass elemTbl = storeMgr.getDatastoreClass(mmd.getCollection().getElementType(), clr);
subStmt = new SelectStatement(stmt, storeMgr, elemTbl, null, null);
subStmt.setClassLoaderResolver(clr);
JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
// Restrict to collection owner
JavaTypeMapping ownerMapping = null;
if (mmd.getMappedBy() != null) {
ownerMapping = elemTbl.getMemberMapping(mmd.getRelatedMemberMetaData(clr)[0]);
} else {
ownerMapping = elemTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
SQLExpression ownerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, collExpr.getSQLTable(), collExpr.getSQLTable().getTable().getIdMapping());
subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
if (elemIsUnbound) {
SQLExpression elemIdExpr = null;
if (!elemType.equals(mmd.getCollection().getElementType())) {
// Variable is defined as a subclass of the declared type so add extra join to variable type
DatastoreClass varTbl = storeMgr.getDatastoreClass(elemType, clr);
SQLTable varSqlTbl = subStmt.join(JoinType.INNER_JOIN, subStmt.getPrimaryTable(), elemTbl.getIdMapping(), null, varTbl, null, varTbl.getIdMapping(), null, null, null, true, null);
elemIdExpr = exprFactory.newExpression(subStmt, varSqlTbl, varTbl.getIdMapping());
} else {
elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), elemTbl.getIdMapping());
}
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(varName, elemCmd, elemIdExpr.getSQLTable(), elemIdExpr.getJavaTypeMapping());
} else {
// Add restrict to element
SQLExpression elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), elemTbl.getIdMapping());
addRestrictionOnElement(subStmt, elemIdExpr, elemExpr);
}
}
return new BooleanSubqueryExpression(stmt, "EXISTS", subStmt);
}
use of org.datanucleus.metadata.AbstractClassMetaData in project datanucleus-rdbms by datanucleus.
the class ClassTable method getMetaDataForMember.
/**
* Acessor for the FieldMetaData for the field with the specified name.
* Searches the MetaData of all classes managed by this table.
* Doesn't allow for cases where the table manages subclasses with the same field name.
* In that case you should use the equivalent method passing FieldMetaData.
* TODO Support subclasses with fields of the same name
* TODO Use of this is discouraged since the fieldName is not fully qualified
* and if a superclass-table inheritance is used we could have 2 fields of that name here.
* @param memberName the field/property name
* @return metadata for the member
*/
AbstractMemberMetaData getMetaDataForMember(String memberName) {
// TODO Dont search "cmd" since it is included in "managedClassMetaData"
AbstractMemberMetaData mmd = cmd.getMetaDataForMember(memberName);
if (mmd == null) {
Iterator<AbstractClassMetaData> iter = managedClassMetaData.iterator();
while (iter.hasNext()) {
AbstractClassMetaData theCmd = iter.next();
final AbstractMemberMetaData foundMmd = theCmd.getMetaDataForMember(memberName);
if (foundMmd != null) {
if (mmd != null && (!mmd.toString().equalsIgnoreCase(foundMmd.toString()) || mmd.getType() != foundMmd.getType())) {
final String errMsg = "Table " + getIdentifier() + " manages at least 2 subclasses that both define a field \"" + memberName + "\", " + "and the fields' metadata is different or they have different type! That means you can get e.g. wrong fetch results.";
NucleusLogger.DATASTORE_SCHEMA.error(errMsg);
throw new NucleusException(errMsg).setFatal();
}
mmd = foundMmd;
}
}
}
return mmd;
}
use of org.datanucleus.metadata.AbstractClassMetaData in project datanucleus-rdbms by datanucleus.
the class ClassTable method getExpectedCandidateKeys.
/**
* Accessor for the expected candidate keys for this table.
* @return The expected candidate keys.
*/
protected List<CandidateKey> getExpectedCandidateKeys() {
assertIsInitialized();
// The candidate keys required by the basic table
List<CandidateKey> candidateKeys = super.getExpectedCandidateKeys();
// Add any constraints required for a FK map
Iterator<CandidateKey> cks = candidateKeysByMapField.values().iterator();
while (cks.hasNext()) {
CandidateKey ck = cks.next();
candidateKeys.add(ck);
}
// Add on any user-required candidate keys for the fields
Set fieldNumbersSet = memberMappingsMap.keySet();
Iterator iter = fieldNumbersSet.iterator();
while (iter.hasNext()) {
AbstractMemberMetaData fmd = (AbstractMemberMetaData) iter.next();
JavaTypeMapping fieldMapping = memberMappingsMap.get(fmd);
if (fieldMapping instanceof EmbeddedPCMapping) {
// Add indexes for fields of this embedded PC object
EmbeddedPCMapping embMapping = (EmbeddedPCMapping) fieldMapping;
for (int i = 0; i < embMapping.getNumberOfJavaTypeMappings(); i++) {
JavaTypeMapping embFieldMapping = embMapping.getJavaTypeMapping(i);
UniqueMetaData umd = embFieldMapping.getMemberMetaData().getUniqueMetaData();
if (umd != null) {
CandidateKey ck = TableUtils.getCandidateKeyForField(this, umd, embFieldMapping);
if (ck != null) {
candidateKeys.add(ck);
}
}
}
} else {
// Add any required candidate key for this field
UniqueMetaData umd = fmd.getUniqueMetaData();
if (umd != null) {
CandidateKey ck = TableUtils.getCandidateKeyForField(this, umd, fieldMapping);
if (ck != null) {
candidateKeys.add(ck);
}
}
}
}
// Add on any user-required candidate keys for the class(es) as a whole (composite keys)
Iterator<AbstractClassMetaData> cmdIter = managedClassMetaData.iterator();
while (cmdIter.hasNext()) {
AbstractClassMetaData thisCmd = cmdIter.next();
List<UniqueMetaData> classCKs = thisCmd.getUniqueMetaData();
if (classCKs != null) {
for (UniqueMetaData unimd : classCKs) {
CandidateKey ck = getCandidateKeyForUniqueMetaData(unimd);
if (ck != null) {
candidateKeys.add(ck);
}
}
}
}
if (cmd.getIdentityType() == IdentityType.APPLICATION) {
// Make sure there is no reuse of PK fields that cause a duplicate index for the PK. Remove it if required
PrimaryKey pk = getPrimaryKey();
Iterator<CandidateKey> candidatesIter = candidateKeys.iterator();
while (candidatesIter.hasNext()) {
CandidateKey key = candidatesIter.next();
if (key.getColumnList().equals(pk.getColumnList())) {
NucleusLogger.DATASTORE_SCHEMA.debug("Candidate key " + key + " is for the same columns as the PrimaryKey so being removed from expected set of candidates. PK is always unique");
candidatesIter.remove();
}
}
}
return candidateKeys;
}
use of org.datanucleus.metadata.AbstractClassMetaData 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()));
}
}
}
}
Aggregations