private static void setStatementExpressionForFieldWithNoDatastoreColumns(QueryExpression qs,
DatastoreIdentifier tableIdentifier,
JavaTypeMapping m,
StatementExpressionIndex statementExpressionIndex)
{
AbstractMemberMetaData fmd = m.getFieldMetaData();
ClassLoaderResolver clr = qs.getClassLoaderResolver();
int relationType = fmd.getRelationType(clr);
if (relationType == Relation.ONE_TO_ONE_BI)
{
if (fmd.getMappedBy() != null)
{
// "mapped-by" at this side
// 1-1 bidirectional single FK relation, with FK in source table.
// This field is not stored, but instead a foreign is set in the source table which stores a reference to this (target table).
// A FK is set in the source table refering to the target table.
// Do a LEFT OUTER JOIN to the related (source) table(s) to pick up the identifier value of this.
/*
* For example :-
* TABLE A (TARGET) TABLE B (SOURCE)
* ID ID A_ID (FK)
* -- -- ----
* 18 21 18
*
* Class A Class B
* { {
* B b; A a;
* } }
*/
int[] colNums = null;
MappedStoreManager storeMgr = qs.getStoreManager();
JavaTypeMapping[] sourceMappings = null;
DatastoreClass[] sourceTables = null;
if (m instanceof ReferenceMapping)
{
// Reference field (with "n" implementations)
JavaTypeMapping[] refMappings = ((ReferenceMapping)m).getJavaTypeMapping();
sourceTables = new DatastoreClass[refMappings.length];
sourceMappings = new JavaTypeMapping[refMappings.length];
for (int i=0;i<refMappings.length;i++)
{
sourceTables[i] = storeMgr.getDatastoreClass(refMappings[i].type, qs.getClassLoaderResolver());
sourceMappings[i] = sourceTables[i].getFieldMapping(fmd.getMappedBy());
}
}
else
{
// PC field
sourceTables = new DatastoreClass[1];
sourceMappings = new JavaTypeMapping[1];
sourceTables[0] = storeMgr.getDatastoreClass(fmd.getTypeName(), qs.getClassLoaderResolver());
sourceMappings[0] = sourceTables[0].getFieldMapping(fmd.getMappedBy());
}
for (int i=0;i<sourceMappings.length;i++)
{
// Do a LEFT OUTER JOIN for this sourceMapping back to the target id column(s)
// TODO Move this hardcoded table name out into the calling class so it controls the names of all table aliases
DatastoreIdentifier sourceTableIdentifier =
storeMgr.getIdentifierFactory().newIdentifier(IdentifierFactory.TABLE,
"SOURCECLASS" + fmd.getAbsoluteFieldNumber() + "_" + i);
LogicSetExpression sourceTableExpr = qs.newTableExpression(sourceTables[i], sourceTableIdentifier, true)[0];
// Left outer join from target ID to the mapped-by field on the source class
ScalarExpression sourceExpr = sourceMappings[i].newScalarExpression(qs, sourceTableExpr);
ScalarExpression targetExpr;
if (tableIdentifier != null)
{
LogicSetExpression targetTableExpr;
if (qs.getTableExpression(tableIdentifier) == null)
{
targetTableExpr = qs.newTableExpression(m.getDatastoreContainer(), tableIdentifier);
}
else
{
targetTableExpr = qs.getTableExpression(tableIdentifier);
}
targetExpr = m.getDatastoreContainer().getIDMapping().newScalarExpression(qs, targetTableExpr);
}
else
{
targetExpr = m.getDatastoreContainer().getIDMapping().newScalarExpression(qs,
qs.getMainTableExpression());
}
qs.leftOuterJoin(sourceExpr, targetExpr, sourceTableExpr, true, true);
// Select the Id column(s) of the source class (via the Left Outer Join)
int[] columnNumbersByField = qs.select(sourceTableIdentifier, sourceTables[i].getIDMapping(), true);
// Copy these column numbers into our overall column numbers set
if (sourceMappings.length == 1)
{
// We only have one source so just reference these
colNums = columnNumbersByField;
}
else if (colNums != null)
{
// Append to the end of where we have got to
int[] tmpColNums = colNums;
colNums = new int[tmpColNums.length + columnNumbersByField.length];
for (int j=0;j<tmpColNums.length;j++)
{
colNums[j] = tmpColNums[j];
}
for (int j=0;j<columnNumbersByField.length;j++)
{
colNums[tmpColNums.length+j] = columnNumbersByField[j];
}
tmpColNums = null;
}
else
{
// Add to the start of our column numbers
colNums = new int[columnNumbersByField.length];
for (int j=0;j<columnNumbersByField.length;j++)
{
colNums[j] = columnNumbersByField[j];
}
}
}
statementExpressionIndex.setExpressionIndex(colNums);
}
}
else if (relationType == Relation.MANY_TO_ONE_BI)
{
AbstractMemberMetaData[] relatedMmds = fmd.getRelatedMemberMetaData(clr);
// TODO Cater for more than 1 related field
if (fmd.getJoinMetaData() != null || relatedMmds[0].getJoinMetaData() != null)
{
// 1-N bidirectional join table relation.
// Do a LEFT OUTER JOIN to the join table to pick up the value.
MappedStoreManager storeMgr = qs.getStoreManager();
DatastoreContainerObject joinTable = storeMgr.getDatastoreContainerObject(relatedMmds[0]);
JavaTypeMapping referenceMapping = null;
JavaTypeMapping selectMapping = null;
DatastoreElementContainer collTable = (DatastoreElementContainer)joinTable;
referenceMapping = collTable.getElementMapping();
selectMapping = collTable.getOwnerMapping();
DatastoreObject mainTable = qs.getMainTableExpression().getMainTable();
if (!mainTable.equals(joinTable))
{
// Statement selects the element table and the owner column should be selected
// Join across to the join table, and select the owner mapping of the join table
// TODO Move this hardcoded table name out into the calling class so it controls the names of all table aliases
DatastoreIdentifier joinTableIdentifier =
storeMgr.getIdentifierFactory().newIdentifier(IdentifierFactory.TABLE,
"JOINTABLE" + fmd.getAbsoluteFieldNumber());
LogicSetExpression table_expr_sub = qs.newTableExpression(joinTable, joinTableIdentifier, true)[0];
// Left outer join from our Id to the mapped-by field on the other class
ScalarExpression subExpr = referenceMapping.newScalarExpression(qs, table_expr_sub);
ScalarExpression schExpr = null;