/// <summary> /// For a collection role, return a list of associations to be fetched by outerjoin /// </summary> private void WalkCollectionTree(IQueryableCollection persister, string alias, string path, string subPathAlias, int currentDepth) { if (persister.IsOneToMany) { WalkEntityTree((IOuterJoinLoadable)persister.ElementPersister, alias, path, currentDepth); } else { IType type = persister.ElementType; if (type.IsAssociationType) { // a many-to-many // decrement currentDepth here to allow join across the association table // without exceeding MAX_FETCH_DEPTH (i.e. the "currentDepth - 1" bit) IAssociationType associationType = (IAssociationType)type; string[] aliasedLhsColumns = persister.GetElementColumnNames(alias); string[] lhsColumns = persister.ElementColumnNames; // if the current depth is 0, the root thing being loaded is the // many-to-many collection itself. Here, it is alright to use // an inner join... bool useInnerJoin = currentDepth == 0; var joinType = GetJoinType( associationType, persister.FetchMode, path, subPathAlias, persister.TableName, lhsColumns, !useInnerJoin, currentDepth - 1, null); AddAssociationToJoinTreeIfNecessary( associationType, aliasedLhsColumns, alias, path, subPathAlias, currentDepth - 1, joinType); } else if (type.IsComponentType) { WalkCompositeElementTree( (IAbstractComponentType)type, persister.ElementColumnNames, persister, alias, path, subPathAlias, currentDepth); } } }
IASTNode CreateFromFilterElement(IASTNode filterEntity, IASTNode alias) { var fromElementFound = true; var fromElement = _currentFromClause.GetFromElement(alias.Text) ?? _currentFromClause.GetFromElementByClassName(filterEntity.Text); if (fromElement == null) { fromElementFound = false; fromElement = _currentFromClause.AddFromElement(filterEntity.Text, alias); } FromClause fromClause = fromElement.FromClause; IQueryableCollection persister = _sessionFactoryHelper.GetCollectionPersister(_collectionFilterRole); // Get the names of the columns used to link between the collection // owner and the collection elements. String[] keyColumnNames = persister.KeyColumnNames; String fkTableAlias = persister.IsOneToMany ? fromElement.TableAlias : fromClause.AliasGenerator.CreateName(_collectionFilterRole); JoinSequence join = _sessionFactoryHelper.CreateJoinSequence(); join.SetRoot(persister, fkTableAlias); if (!persister.IsOneToMany) { join.AddJoin((IAssociationType)persister.ElementType, fromElement.TableAlias, JoinType.InnerJoin, persister.GetElementColumnNames(fkTableAlias)); } join.AddCondition(fkTableAlias, keyColumnNames, " = ", true); fromElement.JoinSequence = join; fromElement.Filter = true; if (log.IsDebugEnabled()) { log.Debug("createFromFilterElement() : processed filter FROM element."); } if (fromElementFound) { return((IASTNode)adaptor.Nil()); } return(fromElement); }
private void PrepareForIndex(QueryTranslator q) { IQueryableCollection collPersister = q.GetCollectionPersister(collectionRole); if (!collPersister.HasIndex) { throw new QueryException("unindexed collection before []"); } string[] indexCols = collPersister.IndexColumnNames; if (indexCols.Length != 1) { throw new QueryException("composite-index appears in []: " + path); } JoinSequence fromJoins = new JoinSequence(q.Factory) .SetUseThetaStyle(useThetaStyleJoin) .SetRoot(collPersister, collectionName) .SetNext(joinSequence.Copy()); if (!continuation) { AddJoin(collectionName, collPersister.CollectionType); } joinSequence.AddCondition(new SqlString(collectionName + '.' + indexCols[0] + " = ")); CollectionElement elem = new CollectionElement(); elem.ElementColumns = collPersister.GetElementColumnNames(collectionName); elem.Type = collPersister.ElementType; elem.IsOneToMany = collPersister.IsOneToMany; elem.Alias = collectionName; elem.JoinSequence = joinSequence; collectionElements.Add(elem); //addlast SetExpectingCollectionIndex(); q.AddCollection(collectionName, collectionRole); q.AddJoin(collectionName, fromJoins); }
/// <summary> /// For a collection role, return a list of associations to be fetched by outerjoin /// </summary> private void WalkCollectionTree(IQueryableCollection persister, string alias, string path, int currentDepth) { if (persister.IsOneToMany) { WalkEntityTree((IOuterJoinLoadable)persister.ElementPersister, alias, path, currentDepth); } else { IType type = persister.ElementType; if (type.IsAssociationType) { // a many-to-many // decrement currentDepth here to allow join across the association table // without exceeding MAX_FETCH_DEPTH (i.e. the "currentDepth - 1" bit) IAssociationType associationType = (IAssociationType)type; string[] aliasedLhsColumns = persister.GetElementColumnNames(alias); string[] lhsColumns = persister.ElementColumnNames; // if the current depth is 0, the root thing being loaded is the // many-to-many collection itself. Here, it is alright to use // an inner join... bool useInnerJoin = currentDepth == 0; JoinType joinType = GetJoinType(associationType, persister.FetchMode, path, persister.TableName, lhsColumns, !useInnerJoin, currentDepth - 1, null); AddAssociationToJoinTreeIfNecessary(associationType, aliasedLhsColumns, alias, path, currentDepth - 1, joinType); } else if (type.IsComponentType) { WalkCompositeElementTree((IAbstractComponentType)type, persister.ElementColumnNames, persister, alias, path, currentDepth); } } }
public override void Resolve(bool generateJoin, bool implicitJoin, string classAlias, IASTNode parent) { if (IsResolved) { return; } FromReferenceNode collectionNode = ( FromReferenceNode )GetChild(0); SessionFactoryHelperExtensions sessionFactoryHelper = SessionFactoryHelper; collectionNode.ResolveIndex(this); // Fully resolve the map reference, create implicit joins. IType type = collectionNode.DataType; if (!type.IsCollectionType) { throw new SemanticException("The [] operator cannot be applied to type " + type); } string collectionRole = (( CollectionType )type).Role; IQueryableCollection queryableCollection = sessionFactoryHelper.RequireQueryableCollection(collectionRole); if (!queryableCollection.HasIndex) { throw new QueryException("unindexed fromElement before []: " + collectionNode.Path); } // Generate the inner join -- The elements need to be joined to the collection they are in. FromElement fromElement = collectionNode.FromElement; String elementTable = fromElement.TableAlias; FromClause fromClause = fromElement.FromClause; String path = collectionNode.Path; FromElement elem = fromClause.FindCollectionJoin(path); if (elem == null) { FromElementFactory factory = new FromElementFactory(fromClause, fromElement, path); elem = factory.CreateCollectionElementsJoin(queryableCollection, elementTable); if (Log.IsDebugEnabled) { Log.Debug("No FROM element found for the elements of collection join path " + path + ", created " + elem); } } else { if (Log.IsDebugEnabled) { Log.Debug("FROM element found for collection join path " + path); } } // The 'from element' that represents the elements of the collection. FromElement = fromElement; // Add the condition to the join sequence that qualifies the indexed element. IASTNode selector = GetChild(1); if (selector == null) { throw new QueryException("No index value!"); } // Sometimes use the element table alias, sometimes use the... umm... collection table alias (many to many) String collectionTableAlias = elementTable; if (elem.CollectionTableAlias != null) { collectionTableAlias = elem.CollectionTableAlias; } // TODO: get SQL rendering out of here, create an AST for the join expressions. // Use the SQL generator grammar to generate the SQL text for the index expression. JoinSequence joinSequence = fromElement.JoinSequence; string[] indexCols = queryableCollection.IndexColumnNames; if (indexCols.Length != 1) { throw new QueryException("composite-index appears in []: " + collectionNode.Path); } SqlGenerator gen = new SqlGenerator(SessionFactoryHelper.Factory, new CommonTreeNodeStream(selector)); try { gen.simpleExpr(); //TODO: used to be exprNoParens! was this needed? } catch (RecognitionException e) { throw new QueryException(e.Message, e); } string selectorExpression = gen.GetSQL().ToString(); joinSequence.AddCondition(new SqlString(collectionTableAlias + '.' + indexCols[0] + " = " + selectorExpression)); //joinSequence.AddCondition(collectionTableAlias, new string[] { indexCols[0] }, selectorExpression, false); IList <IParameterSpecification> paramSpecs = gen.GetCollectedParameters(); if (paramSpecs != null) { switch (paramSpecs.Count) { case 0: // nothing to do break; case 1: IParameterSpecification paramSpec = paramSpecs[0]; paramSpec.ExpectedType = queryableCollection.IndexType; fromElement.SetIndexCollectionSelectorParamSpec(paramSpec); break; default: fromElement.SetIndexCollectionSelectorParamSpec( new AggregatedIndexCollectionSelectorParameterSpecifications(paramSpecs) ); break; } } // Now, set the text for this node. It should be the element columns. String[] elementColumns = queryableCollection.GetElementColumnNames(elementTable); Text = elementColumns[0]; IsResolved = true; }
public string[] ToColumns(string alias, string propertyName) { string[] cols; switch (propertyName) { case CollectionPropertyNames.Elements: return(memberPersister.GetElementColumnNames(alias)); case CollectionPropertyNames.Indices: if (!memberPersister.HasIndex) { throw new QueryException("unindexed collection before indices()"); } return(memberPersister.GetIndexColumnNames(alias)); case CollectionPropertyNames.Size: cols = memberPersister.KeyColumnNames; return(new string[] { "count(" + alias + '.' + cols[0] + ')' }); case CollectionPropertyNames.MaxIndex: if (!memberPersister.HasIndex) { throw new QueryException("unindexed collection in maxIndex()"); } cols = memberPersister.GetIndexColumnNames(alias); if (cols.Length != 1) { throw new QueryException("composite collection index in maxIndex()"); } return(new string[] { "max(" + cols[0] + ')' }); case CollectionPropertyNames.MinIndex: if (!memberPersister.HasIndex) { throw new QueryException("unindexed collection in minIndex()"); } cols = memberPersister.GetIndexColumnNames(alias); if (cols.Length != 1) { throw new QueryException("composite collection index in minIndex()"); } return(new string[] { "min(" + cols[0] + ')' }); case CollectionPropertyNames.MaxElement: cols = memberPersister.GetElementColumnNames(alias); if (cols.Length != 1) { throw new QueryException("composite collection element in maxElement()"); } return(new string[] { "max(" + cols[0] + ')' }); case CollectionPropertyNames.MinElement: cols = memberPersister.GetElementColumnNames(alias); if (cols.Length != 1) { throw new QueryException("composite collection element in minElement()"); } return(new System.String[] { "min(" + cols[0] + ')' }); default: throw new QueryException("illegal syntax near collection: " + propertyName); } }