public override void Resolve(bool generateJoin, bool implicitJoin, string classAlias, IASTNode parent) { // If this dot has already been resolved, stop now. if (IsResolved) { return; } IType propertyType = PrepareLhs(); // Prepare the left hand side and get the data type. // If there is no data type for this node, and we're at the end of the path (top most dot node), then // this might be a Java constant. if (propertyType == null) { if (parent == null) { Walker.LiteralProcessor.LookupConstant(this); } // If the propertyType is null and there isn't a parent, just // stop now... there was a problem resolving the node anyway. return; } if (propertyType.IsComponentType) { // The property is a component... CheckLhsIsNotCollection(); DereferenceComponent(parent); InitText(); } else if (propertyType.IsEntityType) { // The property is another class.. CheckLhsIsNotCollection(); DereferenceEntity(( EntityType )propertyType, implicitJoin, classAlias, generateJoin, parent); InitText(); } else if (propertyType.IsCollectionType) { // The property is a collection... CheckLhsIsNotCollection(); DereferenceCollection((CollectionType)propertyType, implicitJoin, false, classAlias); } else { // Otherwise, this is a primitive type. if (!CollectionProperties.IsAnyCollectionProperty(_propertyName)) { CheckLhsIsNotCollection(); } _dereferenceType = DerefPrimitive; InitText(); } IsResolved = true; }
private void DereferenceCollection(CollectionType collectionType, bool implicitJoin, bool indexed, string classAlias) { _dereferenceType = DerefCollection; string role = collectionType.Role; //foo.bars.size (also handles deprecated stuff like foo.bars.maxelement for backwardness) IASTNode sibling = NextSibling; bool isSizeProperty = sibling != null && CollectionProperties.IsAnyCollectionProperty(sibling.Text); if (isSizeProperty) { indexed = true; //yuck!} } IQueryableCollection queryableCollection = SessionFactoryHelper.RequireQueryableCollection(role); string propName = Path; FromClause currentFromClause = Walker.CurrentFromClause; if (Walker.StatementType != HqlSqlWalker.SELECT && indexed && classAlias == null) { // should indicate that we are processing an INSERT/UPDATE/DELETE // query with a subquery implied via a collection property // function. Here, we need to use the table name itself as the // qualification alias. // TODO : verify this works for all databases... // TODO : is this also the case in non-"indexed" scenarios? string alias = GetLhs().FromElement.Queryable.TableName; _columns = FromElement.ToColumns(alias, _propertyPath, false, true); } //We do not look for an existing join on the same path, because //it makes sense to join twice on the same collection role FromElementFactory factory = new FromElementFactory( currentFromClause, GetLhs().FromElement, propName, classAlias, GetColumns(), implicitJoin ); FromElement elem = factory.CreateCollection(queryableCollection, role, _joinType, _fetch, indexed); if (Log.IsDebugEnabled) { Log.Debug("dereferenceCollection() : Created new FROM element for " + propName + " : " + elem); } SetImpliedJoin(elem); FromElement = elem; // This 'dot' expression now refers to the resulting from element. if (isSizeProperty) { elem.Text = ""; elem.UseWhereFragment = false; } if (!implicitJoin) { IEntityPersister entityPersister = elem.EntityPersister; if (entityPersister != null) { Walker.AddQuerySpaces(entityPersister.QuerySpaces); } } Walker.AddQuerySpaces(queryableCollection.CollectionSpaces); // Always add the collection's query spaces. }