private void DereferenceEntity(EntityType entityType, bool implicitJoin, string classAlias, bool generateJoin, IASTNode parent) { CheckForCorrelatedSubquery("dereferenceEntity"); // three general cases we check here as to whether to render a physical SQL join: // 1) is our parent a DotNode as well? If so, our property reference is // being further de-referenced... // 2) is this a DML statement // 3) we were asked to generate any needed joins (generateJoins==true) *OR* // we are currently processing a select or from clause // (an additional check is the REGRESSION_STYLE_JOIN_SUPPRESSION check solely intended for the test suite) // // The REGRESSION_STYLE_JOIN_SUPPRESSION is an additional check // intended solely for use within the test suite. This forces the // implicit join resolution to behave more like the classic parser. // The underlying issue is that classic translator is simply wrong // about its decisions on whether or not to render an implicit join // into a physical SQL join in a lot of cases. The piece it generally // tends to miss is that INNER joins effect the results by further // restricting the data set! A particular manifestation of this is // the fact that the classic translator will skip the physical join // for ToOne implicit joins *if the query is shallow*; the result // being that Query.list() and Query.iterate() could return // different number of results! DotNode parentAsDotNode = null; string property = _propertyName; bool joinIsNeeded; //For nullable entity comparisons we always need to add join (like not constrained one-to-one or not-found ignore associations) bool comparisonWithNullableEntity = entityType.IsNullable && Walker.IsComparativeExpressionClause; if (IsDotNode(parent)) { // our parent is another dot node, meaning we are being further dereferenced. // thus we need to generate a join unless the parent refers to the associated // entity's PK (because 'our' table would know the FK). parentAsDotNode = ( DotNode )parent; property = parentAsDotNode._propertyName; joinIsNeeded = generateJoin && ((Walker.IsSelectStatement && comparisonWithNullableEntity) || !IsReferenceToPrimaryKey(parentAsDotNode._propertyName, entityType)); } else if (!Walker.IsSelectStatement) { // in non-select queries, the only time we should need to join is if we are in a subquery from clause joinIsNeeded = Walker.CurrentStatementType == HqlSqlWalker.SELECT && Walker.IsInFrom; } else if (REGRESSION_STYLE_JOIN_SUPPRESSION) { // this is the regression style determination which matches the logic of the classic translator joinIsNeeded = generateJoin && (!Walker.IsInSelect || !Walker.IsShallowQuery); } else { joinIsNeeded = generateJoin || (Walker.IsInSelect && !Walker.IsInCase) || (Walker.IsInFrom && !Walker.IsComparativeExpressionClause) || comparisonWithNullableEntity; } if (joinIsNeeded) { var forceLeftJoin = comparisonWithNullableEntity && Walker.IsNullComparison; DereferenceEntityJoin(classAlias, entityType, implicitJoin, parent, forceLeftJoin); if (comparisonWithNullableEntity) { _columns = FromElement.GetIdentityColumns(); } } else { DereferenceEntityIdentifier(property, parentAsDotNode); } }