|
@@ -1776,37 +1776,46 @@ class DBObjectSearch extends DBSearch
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- // First query built upon on the leaf (ie current) class
|
|
|
|
|
|
+ // First query built from the root, adding all tables including the leaf
|
|
|
|
+ // Before N.1065 we were joining from the leaf first, but this wasn't a good choice :
|
|
|
|
+ // most of the time (obsolescence, friendlyname, ...) we want to get a root attribute !
|
|
//
|
|
//
|
|
- self::DbgTrace("Main (=leaf) class, call MakeSQLObjectQuerySingleTable()");
|
|
|
|
- if (MetaModel::HasTable($sClass))
|
|
|
|
|
|
+ $oSelectBase = null;
|
|
|
|
+ $aClassHierarchy = MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL, true);
|
|
|
|
+ $bIsClassStandaloneClass = (count($aClassHierarchy) == 1);
|
|
|
|
+ foreach($aClassHierarchy as $sSomeClass)
|
|
{
|
|
{
|
|
- $oSelectBase = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sClass, $aExtKeys, $aValues);
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- $oSelectBase = null;
|
|
|
|
-
|
|
|
|
- // As the join will not filter on the expected classes, we have to specify it explicitely
|
|
|
|
- $sExpectedClasses = implode("', '", MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL));
|
|
|
|
- $oFinalClassRestriction = Expression::FromOQL("`$sClassAlias`.finalclass IN ('$sExpectedClasses')");
|
|
|
|
- $oBuild->m_oQBExpressions->AddCondition($oFinalClassRestriction);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Then we join the queries of the eventual parent classes (compound model)
|
|
|
|
- foreach(MetaModel::EnumParentClasses($sClass) as $sParentClass)
|
|
|
|
- {
|
|
|
|
- if (!MetaModel::HasTable($sParentClass)) continue;
|
|
|
|
|
|
+ if (!MetaModel::HasTable($sSomeClass))
|
|
|
|
+ {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
|
|
- self::DbgTrace("Parent class: $sParentClass... let's call MakeSQLObjectQuerySingleTable()");
|
|
|
|
- $oSelectParentTable = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sParentClass, $aExtKeys, $aValues);
|
|
|
|
|
|
+ self::DbgTrace("Adding join from root to leaf: $sSomeClass... let's call MakeSQLObjectQuerySingleTable()");
|
|
|
|
+ $oSelectParentTable = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sSomeClass, $aExtKeys, $aValues);
|
|
if (is_null($oSelectBase))
|
|
if (is_null($oSelectBase))
|
|
{
|
|
{
|
|
$oSelectBase = $oSelectParentTable;
|
|
$oSelectBase = $oSelectParentTable;
|
|
|
|
+ if (!$bIsClassStandaloneClass && (MetaModel::IsRootClass($sSomeClass)))
|
|
|
|
+ {
|
|
|
|
+ // As we're linking to root class first, we're adding a where clause on the finalClass attribute :
|
|
|
|
+ // COALESCE($sRootClassFinalClass IN ('$sExpectedClasses'), 1)
|
|
|
|
+ // If we don't, the child classes can be removed in the query optimisation phase, including the leaf that was queried
|
|
|
|
+ // So we still need to filter records to only those corresponding to the child classes !
|
|
|
|
+ // The coalesce is mandatory if we have a polymorphic query (left join)
|
|
|
|
+ $oClassListExpr = ListExpression::FromScalars(MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL));
|
|
|
|
+ $sFinalClassSqlColumnName = MetaModel::DBGetClassField($sSomeClass);
|
|
|
|
+ $oClassExpr = new FieldExpression($sFinalClassSqlColumnName, $oSelectBase->GetTableAlias());
|
|
|
|
+ $oInExpression = new BinaryExpression($oClassExpr, 'IN', $oClassListExpr);
|
|
|
|
+ $oTrueExpression = new TrueExpression();
|
|
|
|
+ $aCoalesceAttr = array($oInExpression, $oTrueExpression);
|
|
|
|
+ $oFinalClassRestriction = new FunctionExpression("COALESCE", $aCoalesceAttr);
|
|
|
|
+
|
|
|
|
+ $oBuild->m_oQBExpressions->AddCondition($oFinalClassRestriction);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- $oSelectBase->AddInnerJoin($oSelectParentTable, $sKeyField, MetaModel::DBGetKey($sParentClass));
|
|
|
|
|
|
+ $oSelectBase->AddInnerJoin($oSelectParentTable, $sKeyField, MetaModel::DBGetKey($sSomeClass));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|