AbstractClassMetaData relatedCmd =
storeMgr.getMetaDataManager().getMetaDataForClass(mmd.getType(), clr);
if (relatedCmd != null)
{
// Find the table of the related class
DatastoreClass relatedTbl = storeMgr.getDatastoreClass(relatedCmd.getFullClassName(), clr);
if (relatedTbl == null)
{
// Class doesn't have its own table (subclass-table) so find where it persists
AbstractClassMetaData[] ownerParentCmds =
storeMgr.getClassesManagingTableForClass(relatedCmd, clr);
if (ownerParentCmds.length > 1)
{
throw new NucleusUserException("Relation (" + mmd.getFullFieldName() +
") with multiple related tables (using subclass-table). Not supported");
}
relatedTbl = storeMgr.getDatastoreClass(ownerParentCmds[0].getFullClassName(), clr);
}
String requiredGroupName = null;
if (sourceSqlTbl.getGroupName() != null)
{
// JPQL will have table groups defined already, named as per "alias.fieldName"
requiredGroupName = sourceSqlTbl.getGroupName() + "." + mmd.getName();
}
SQLTable relatedSqlTbl = stmt.getTable(relatedTbl, requiredGroupName);
if (relatedSqlTbl == null)
{
// Join the 1-1 relation
relatedSqlTbl = addJoinForOneToOneRelation(stmt,
m, sqlTbl, relatedTbl.getIdMapping(), relatedTbl, null, null, tableGroupName, null);
}
StatementClassMapping subMappingDefinition =
new StatementClassMapping(mmd.getClassName(), mmd.getName());
selectFetchPlanOfSourceClassInStatement(stmt, subMappingDefinition, fetchPlan,
relatedSqlTbl, relatedCmd, maxFetchPlanLimit-1);
if (mappingDefinition != null)
{
if (relatedCmd.getIdentityType() == IdentityType.APPLICATION)
{
int[] pkFields = relatedCmd.getPKMemberPositions();
int[] pkCols = new int[m.getNumberOfDatastoreMappings()];
int pkColNo = 0;
for (int i=0;i<pkFields.length;i++)
{
StatementMappingIndex pkIdx = subMappingDefinition.getMappingForMemberPosition(pkFields[i]);
int[] pkColNumbers = pkIdx.getColumnPositions();
for (int j=0;j<pkColNumbers.length;j++)
{
pkCols[pkColNo] = pkColNumbers[j];
pkColNo++;
}
}
selectFK = false;
stmtMapping.setColumnPositions(pkCols);
}
else if (relatedCmd.getIdentityType() == IdentityType.DATASTORE)
{
StatementMappingIndex pkIdx = subMappingDefinition.getMappingForMemberPosition(StatementClassMapping.MEMBER_DATASTORE_ID);
selectFK = false;
stmtMapping.setColumnPositions(pkIdx.getColumnPositions());
}
mappingDefinition.addMappingDefinitionForMember(mmd.getAbsoluteFieldNumber(),
subMappingDefinition);
}
}
else
{
// TODO 1-1 interface relation
}
}
}
if (selectFK)
{
int[] colNumbers = stmt.select(sqlTbl, m, null);
stmtMapping.setColumnPositions(colNumbers);
}
}
else
{
// Select of related objects with FK in other table
if (relationType == Relation.ONE_TO_ONE_BI && mmd.getMappedBy() != null)
{
// 1-1 bidirectional relation with FK in related table
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
AbstractMemberMetaData relatedMmd = relatedMmds[0];
String[] clsNames = null;
if (mmd.getType().isInterface())
{
if (mmd.getFieldTypes() != null && mmd.getFieldTypes().length == 1)
{
// Use field-type since only one class specified
Class fldTypeCls = clr.classForName(mmd.getFieldTypes()[0]);
if (fldTypeCls.isInterface())
{
// User has specified an interface, so find its implementations
clsNames = mmgr.getClassesImplementingInterface(mmd.getFieldTypes()[0], clr);
}
else
{
// Use user-provided field-type
clsNames = new String[] {mmd.getFieldTypes()[0]};
}
}
if (clsNames == null)
{
clsNames = mmgr.getClassesImplementingInterface(mmd.getTypeName(), clr);
}
}
else
{
clsNames = new String[] { mmd.getTypeName() };
}
DatastoreClass relatedTbl = storeMgr.getDatastoreClass(clsNames[0], clr);
JavaTypeMapping relatedMapping = relatedTbl.getMemberMapping(relatedMmd);
JavaTypeMapping relatedDiscrimMapping = relatedTbl.getDiscriminatorMapping(true);
Object[] discrimValues = null;
JavaTypeMapping relatedTypeMapping = null;
AbstractClassMetaData relatedCmd = relatedMmd.getAbstractClassMetaData();
if (relatedDiscrimMapping != null &&
(relatedCmd.getSuperAbstractClassMetaData() != null || !relatedCmd.getFullClassName().equals(mmd.getTypeName())))
{
// Related table has a discriminator and the field can store other types
List discValueList = null;
for (int i=0;i<clsNames.length;i++)
{
List values = getDiscriminatorValuesForMember(clsNames[i],
relatedDiscrimMapping, storeMgr, clr);
if (discValueList == null)
{
discValueList = values;
}
else
{
discValueList.addAll(values);
}
}
discrimValues = discValueList.toArray(new Object[discValueList.size()]);
}
else if (relatedTbl != relatedMapping.getDatastoreContainer())
{
// The relation is to a base class table, and the type stored is a sub-class
relatedTypeMapping = relatedTbl.getIdMapping();
}
SQLTable relatedSqlTbl = null;
if (relatedTypeMapping == null)
{
// Join the 1-1 relation
relatedSqlTbl = addJoinForOneToOneRelation(stmt,
sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl,
relatedMapping, relatedTbl, null, discrimValues, tableGroupName, null);
// Select the id mapping in the related table
int[] colNumbers = stmt.select(relatedSqlTbl, relatedTbl.getIdMapping(), null);
stmtMapping.setColumnPositions(colNumbers);
}
else
{
DatastoreClass relationTbl = (DatastoreClass)relatedMapping.getDatastoreContainer();
if (relatedTbl != relatedMapping.getDatastoreContainer())
{
if (relatedMapping.isNullable())
{
// Nullable - left outer join from {sourceTable}.ID to {relatedBaseTable}.FK