Example #1
0
        private FromElement CreateManyToMany(
            string role,
            string associatedEntityName,
            string roleAlias,
            IEntityPersister entityPersister,
            EntityType type,
            JoinType joinType)
        {
            FromElement elem;
            SessionFactoryHelperExtensions sfh = _fromClause.SessionFactoryHelper;

            if (_inElementsFunction /*implied*/)
            {
                // For implied many-to-many, just add the end join.
                JoinSequence joinSequence = CreateJoinSequence(roleAlias, joinType);
                elem = CreateJoin(associatedEntityName, roleAlias, joinSequence, type, true);
            }
            else
            {
                // For an explicit many-to-many relationship, add a second join from the intermediate
                // (many-to-many) table to the destination table.  Also, make sure that the from element's
                // idea of the destination is the destination table.
                string   tableAlias        = _fromClause.AliasGenerator.CreateName(entityPersister.EntityName);
                string[] secondJoinColumns = sfh.GetCollectionElementColumns(role, roleAlias);

                // Add the second join, the one that ends in the destination table.
                JoinSequence joinSequence = CreateJoinSequence(roleAlias, joinType);
                joinSequence.AddJoin(sfh.GetElementAssociationType(_collectionType), tableAlias, joinType, secondJoinColumns);
                elem = CreateJoin(associatedEntityName, tableAlias, joinSequence, type, false);
                elem.UseFromFragment = true;
            }
            return(elem);
        }
Example #2
0
        public FromElement CreateElementJoin(IQueryableCollection queryableCollection)
        {
            _implied            = true;  //TODO: always true for now, but not if we later decide to support elements() in the from clause
            _inElementsFunction = true;

            IType elementType = queryableCollection.ElementType;

            if (!elementType.IsEntityType)
            {
                throw new InvalidOperationException("Cannot create element join for a collection of non-entities!");
            }

            _queryableCollection = queryableCollection;

            SessionFactoryHelperExtensions sfh     = _fromClause.SessionFactoryHelper;
            IEntityPersister entityPersister       = queryableCollection.ElementPersister;
            string           tableAlias            = _fromClause.AliasGenerator.CreateName(entityPersister.EntityName);
            string           associatedEntityName  = entityPersister.EntityName;
            IEntityPersister targetEntityPersister = sfh.RequireClassPersister(associatedEntityName);

            // Create the FROM element for the target (the elements of the collection).
            FromElement destination = CreateAndAddFromElement(
                associatedEntityName,
                _classAlias,
                targetEntityPersister,
                (EntityType)queryableCollection.ElementType,
                tableAlias
                );

            // If the join is implied, then don't include sub-classes on the element.
            if (_implied)
            {
                destination.IncludeSubclasses = false;
            }

            _fromClause.AddCollectionJoinFromElementByPath(_path, destination);
            //		origin.addDestination(destination);
            // Add the query spaces.
            _fromClause.Walker.AddQuerySpaces(entityPersister.QuerySpaces);

            CollectionType type      = queryableCollection.CollectionType;
            string         role      = type.Role;
            string         roleAlias = _origin.TableAlias;

            string[]         targetColumns          = sfh.GetCollectionElementColumns(role, roleAlias);
            IAssociationType elementAssociationType = sfh.GetElementAssociationType(type);

            // Create the join element under the from element.
            JoinSequence joinSequence = sfh.CreateJoinSequence(_implied, elementAssociationType, tableAlias, JoinType.InnerJoin, targetColumns);
            FromElement  elem         = InitializeJoin(_path, destination, joinSequence, targetColumns, _origin, false);

            elem.UseFromFragment      = true;           // The associated entity is implied, but it must be included in the FROM.
            elem.CollectionTableAlias = roleAlias;      // The collection alias is the role.
            return(elem);
        }
Example #3
0
        private JoinSequence CreateJoinSequence(string roleAlias, JoinType joinType)
        {
            SessionFactoryHelperExtensions sessionFactoryHelper = _fromClause.SessionFactoryHelper;

            string[] joinColumns = Columns;
            if (_collectionType == null)
            {
                throw new InvalidOperationException("collectionType is null!");
            }
            return(sessionFactoryHelper.CreateJoinSequence(_implied, _collectionType, roleAlias, joinType, joinColumns));
        }
Example #4
0
        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;
        }