示例#1
0
        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);
            }
        }