Пример #1
0
 public ClientJoinExpression(ProjectionExpression projection, IEnumerable<Expression> outerKey, IEnumerable<Expression> innerKey)
     : base(DbExpressionType.ClientJoin, projection.Type)
 {
     this.outerKey = outerKey.ToReadOnly();
     this.innerKey = innerKey.ToReadOnly();
     this.projection = projection;
 }
Пример #2
0
 public OUpdateCommandExpression(IdentifiableExpression identifiable, Expression where, IEnumerable<FieldAssignment> assignments, Expression projector)
     : base(identifiable, where, assignments)
 {
     Projection = new ProjectionExpression(null,
         projector,
         Aggregator.GetAggregator(projector.Type, typeof(IEnumerable<>).MakeGenericType(projector.Type)));
 }
Пример #3
0
 public virtual ProjectionExpression AddOuterJoinTest(ProjectionExpression proj)
 {
     var test = this.GetOuterJoinTest(proj.Select);
     var select = proj.Select;
     FieldExpression testCol = null;
     // look to see if test expression exists in fields already
     foreach (var col in select.Fields)
     {
         if (test.Equals(col.Expression))
         {
             var colType = this.TypeSystem.GetStorageType(test.Type);
             testCol = new FieldExpression(test.Type, colType, select.Alias, col.Name);
             break;
         }
     }
     if (testCol == null)
     {
         // add expression to projection
         testCol = test as FieldExpression;
         string colName = (testCol != null) ? testCol.Name : "Test";
         colName = proj.Select.Fields.GetAvailableFieldName(colName);
         var colType = this.TypeSystem.GetStorageType(test.Type);
         select = select.AddField(new FieldDeclaration(colName, test, colType));
         testCol = new FieldExpression(test.Type, colType, select.Alias, colName);
     }
     var newProjector = new OuterJoinedExpression(testCol, proj.Projector);
     return new ProjectionExpression(select, newProjector, proj.Aggregator);
 }
Пример #4
0
 protected ClientJoinExpression UpdateClientJoin(ClientJoinExpression join, ProjectionExpression projection, IEnumerable<Expression> outerKey, IEnumerable<Expression> innerKey)
 {
     if (projection != join.Projection || outerKey != join.OuterKey || innerKey != join.InnerKey)
     {
         return new ClientJoinExpression(projection, outerKey, innerKey);
     }
     return join;
 }
Пример #5
0
 protected virtual UpdateCommandExpression UpdateUpdate(OUpdateCommandExpression update, IdentifiableExpression table, Expression where,
     IEnumerable<FieldAssignment> assignments, ProjectionExpression projection)
 {
     if (table != update.Identifiable || where != update.Where || assignments != update.Assignments || projection.Projector != update.Projection.Projector)
     {
         return new OUpdateCommandExpression(table, where, assignments, projection.Projector);
     }
     return update;
 }
Пример #6
0
 protected virtual InsertCommandExpression UpdateInsert(OInsertCommandExpression insert, IdentifiableExpression table,
     IEnumerable<FieldAssignment> assignments, ProjectionExpression projection)
 {
     if (table != insert.Identifiable || assignments != insert.Assignments || projection.Projector != insert.Projection.Projector)
     {
         return new OInsertCommandExpression(table, assignments, projection.Projector);
     }
     return insert;
 }
Пример #7
0
 protected override Expression VisitProjection(ProjectionExpression proj)
 {
     proj = (ProjectionExpression)base.VisitProjection(proj);
     if (proj.Select.From is SelectExpression)
     {
         List<SelectExpression> redundant = RedundantSubqueryGatherer.Gather(proj.Select);
         if (redundant != null)
         {
             proj = SubqueryRemover.Remove(proj, redundant);
         }
     }
     return proj;
 }
        protected override Expression VisitProjection(ProjectionExpression proj)
        {
            if (isTopLevel)
            {
                isTopLevel = false;
                this.currentSelect = proj.Select;
                Expression projector = this.Visit(proj.Projector);
                if (projector != proj.Projector || this.currentSelect != proj.Select)
                {
                    return new ProjectionExpression(this.currentSelect, projector, proj.Aggregator);
                }
                return proj;
            }

            if (proj.IsSingleton && this.CanJoinOnServer(this.currentSelect))
            {
                IdentifiableAlias newAlias = new IdentifiableAlias();
                this.currentSelect = this.currentSelect.AddRedundantSelect(this.language, newAlias);

                // remap any references to the outer select to the new alias;
                SelectExpression source = (SelectExpression)FieldMapper.Map(proj.Select, newAlias, this.currentSelect.Alias);

                // add outer-join test
                ProjectionExpression pex = this.language.AddOuterJoinTest(new ProjectionExpression(source, proj.Projector));

                var pc = FieldProjector.ProjectFields(this.language, pex.Projector, this.currentSelect.Fields, this.currentSelect.Alias, newAlias, proj.Select.Alias);

                JoinExpression join = new JoinExpression(JoinType.OuterApply, this.currentSelect.From, pex.Select, null);

                this.currentSelect = new SelectExpression(this.currentSelect.Alias, pc.Fields, join, null);
                return this.Visit(pc.Projector);
            }

            var saveTop = this.isTopLevel;
            var saveSelect = this.currentSelect;
            this.isTopLevel = true;
            this.currentSelect = null;
            Expression result = base.VisitProjection(proj);
            this.isTopLevel = saveTop;
            this.currentSelect = saveSelect;
            return result;
        }
Пример #9
0
 protected ProjectionExpression UpdateProjection(ProjectionExpression proj, SelectExpression select, Expression projector, LambdaExpression aggregator)
 {
     if (select != proj.Select || projector != proj.Projector || aggregator != proj.Aggregator)
     {
         return new ProjectionExpression(select, projector, aggregator);
     }
     return proj;
 }
Пример #10
0
 public static ProjectionExpression Remove(ProjectionExpression projection, IEnumerable<SelectExpression> selectsToRemove)
 {
     return (ProjectionExpression)new OSubqueryRemover(selectsToRemove).Visit(projection);
 }
Пример #11
0
 public static ProjectionExpression Remove(ProjectionExpression projection, params SelectExpression[] selectsToRemove)
 {
     return Remove(projection, (IEnumerable<SelectExpression>)selectsToRemove);
 }
Пример #12
0
 protected override Expression VisitProjection(ProjectionExpression proj)
 {
     Expression projector = this.Visit(proj.Projector);
     return this.UpdateProjection(proj, proj.Select, projector, proj.Aggregator);
 }
Пример #13
0
        protected virtual bool CompareProjection(ProjectionExpression a, ProjectionExpression b)
        {
            if (!this.Compare(a.Select, b.Select))
                return false;

            var save = this.aliasScope;
            try
            {
                this.aliasScope = new ScopedDictionary<IdentifiableAlias, IdentifiableAlias>(this.aliasScope);
                this.aliasScope.Add(a.Select.Alias, b.Select.Alias);

                return this.Compare(a.Projector, b.Projector)
                    && this.Compare(a.Aggregator, b.Aggregator)
                    && a.IsSingleton == b.IsSingleton;
            }
            finally
            {
                this.aliasScope = save;
            }
        }
Пример #14
0
        public override ProjectionExpression GetQueryExpression(IMappedEntity entity)
        {
            var IdentifiableAlias = new IdentifiableAlias();
            var selectAlias = new IdentifiableAlias();
            var table = new IdentifiableExpression(IdentifiableAlias, entity, this.mapping.GetTableName(entity));

            Expression projector = this.GetEntityExpression(table, entity);
            var pc = FieldProjector.ProjectFields(this.translator.Linguist.Language, projector, null, selectAlias, IdentifiableAlias);

            var proj = new ProjectionExpression(
                new SelectExpression(selectAlias, pc.Fields, table, null),
                pc.Projector
                );

            return (ProjectionExpression)this.Translator.Police.ApplyPolicy(proj, entity.EntityType);
        }
Пример #15
0
 protected override Expression VisitProjection(ProjectionExpression projection)
 {
     // visit mapping in reverse order
     Expression projector = this.Visit(projection.Projector);
     SelectExpression select = (SelectExpression)this.Visit(projection.Select);
     return this.UpdateProjection(projection, select, projector, projection.Aggregator);
 }
Пример #16
0
 protected override Expression VisitProjection(ProjectionExpression proj)
 {
     this.Visit(proj.Projector);
     return proj;
 }
Пример #17
0
        protected virtual Expression BindGroupBy(Expression source, LambdaExpression keySelector, LambdaExpression elementSelector, LambdaExpression resultSelector)
        {
            ProjectionExpression projection = this.VisitSequence(source);

            this.map[keySelector.Parameters[0]] = projection.Projector;
            Expression keyExpr = this.Visit(keySelector.Body);

            Expression elemExpr = projection.Projector;
            if (elementSelector != null)
            {
                this.map[elementSelector.Parameters[0]] = projection.Projector;
                elemExpr = this.Visit(elementSelector.Body);
            }

            // Use ProjectFields to get group-by expressions from key expression
            ProjectedFields keyProjection = this.ProjectFields(keyExpr, projection.Select.Alias, projection.Select.Alias);
            var groupExprs = keyProjection.Fields.Select(c => c.Expression).ToArray();

            // make duplicate of source query as basis of element subquery by visiting the source again
            ProjectionExpression subqueryBasis = this.VisitSequence(source);

            // recompute key fields for group expressions relative to subquery (need these for doing the correlation predicate)
            this.map[keySelector.Parameters[0]] = subqueryBasis.Projector;
            Expression subqueryKey = this.Visit(keySelector.Body);

            // use same projection trick to get group-by expressions based on subquery
            ProjectedFields subqueryKeyPC = this.ProjectFields(subqueryKey, subqueryBasis.Select.Alias, subqueryBasis.Select.Alias);
            var subqueryGroupExprs = subqueryKeyPC.Fields.Select(c => c.Expression).ToArray();
            Expression subqueryCorrelation = this.BuildPredicateWithNullsEqual(subqueryGroupExprs, groupExprs);

            // compute element based on duplicated subquery
            Expression subqueryElemExpr = subqueryBasis.Projector;
            if (elementSelector != null)
            {
                this.map[elementSelector.Parameters[0]] = subqueryBasis.Projector;
                subqueryElemExpr = this.Visit(elementSelector.Body);
            }

            // build subquery that projects the desired element
            var elementAlias = this.GetNextAlias();
            ProjectedFields elementPC = this.ProjectFields(subqueryElemExpr, elementAlias, subqueryBasis.Select.Alias);
            ProjectionExpression elementSubquery =
                new ProjectionExpression(
                    new SelectExpression(elementAlias, elementPC.Fields, subqueryBasis.Select, subqueryCorrelation),
                    elementPC.Projector
                    );

            var alias = this.GetNextAlias();

            // make it possible to tie aggregates back to this group-by
            GroupByInfo info = new GroupByInfo(alias, elemExpr);
            this.groupByMap.Add(elementSubquery, info);

            Expression resultExpr;
            if (resultSelector != null)
            {
                Expression saveGroupElement = this.currentGroupElement;
                this.currentGroupElement = elementSubquery;
                // compute result expression based on key & element-subquery
                this.map[resultSelector.Parameters[0]] = keyProjection.Projector;
                this.map[resultSelector.Parameters[1]] = elementSubquery;
                resultExpr = this.Visit(resultSelector.Body);
                this.currentGroupElement = saveGroupElement;
            }
            else
            {
                // result must be IGrouping<K,E>
                resultExpr =
                    Expression.New(
                        typeof(Grouping<,>).MakeGenericType(keyExpr.Type, subqueryElemExpr.Type).GetConstructors()[0],
                        new Expression[] { keyExpr, elementSubquery }
                        );

                resultExpr = Expression.Convert(resultExpr, typeof(IGrouping<,>).MakeGenericType(keyExpr.Type, subqueryElemExpr.Type));
            }

            ProjectedFields pc = this.ProjectFields(resultExpr, alias, projection.Select.Alias);

            // make it possible to tie aggregates back to this group-by
            NewExpression newResult = this.GetNewExpression(pc.Projector);
            if (newResult != null && newResult.Type.IsGenericType && newResult.Type.GetGenericTypeDefinition() == typeof(Grouping<,>))
            {
                Expression projectedElementSubquery = newResult.Arguments[1];
                this.groupByMap.Add(projectedElementSubquery, info);
            }

            return new ProjectionExpression(
                new SelectExpression(alias, pc.Fields, projection.Select, null, null, groupExprs),
                pc.Projector
                );
        }
        protected override Expression VisitProjection(ProjectionExpression proj)
        {
            SelectExpression save = this.currentSelect;
            this.currentSelect = proj.Select;
            try
            {
                if (!this.isTopLevel)
                {
                    if (this.CanJoinOnClient(this.currentSelect))
                    {
                        // make a query that combines all the constraints from the outer queries into a single select
                        SelectExpression newOuterSelect = (SelectExpression)QueryDuplicator.Duplicate(save);

                        // remap any references to the outer select to the new alias;
                        SelectExpression newInnerSelect = (SelectExpression)FieldMapper.Map(proj.Select, newOuterSelect.Alias, save.Alias);
                        // add outer-join test
                        ProjectionExpression newInnerProjection = this.language.AddOuterJoinTest(new ProjectionExpression(newInnerSelect, proj.Projector));
                        newInnerSelect = newInnerProjection.Select;
                        Expression newProjector = newInnerProjection.Projector;

                        IdentifiableAlias newAlias = new IdentifiableAlias();
                        var pc = FieldProjector.ProjectFields(this.language, newProjector, null, newAlias, newOuterSelect.Alias, newInnerSelect.Alias);

                        JoinExpression join = new JoinExpression(JoinType.OuterApply, newOuterSelect, newInnerSelect, null);
                        SelectExpression joinedSelect = new SelectExpression(newAlias, pc.Fields, join, null, null, null, proj.IsSingleton, null, null, false);

                        // apply client-join treatment recursively
                        this.currentSelect = joinedSelect;
                        newProjector = this.Visit(pc.Projector);

                        // compute keys (this only works if join condition was a single field comparison)
                        List<Expression> outerKeys = new List<Expression>();
                        List<Expression> innerKeys = new List<Expression>();
                        if (this.GetEquiJoinKeyExpressions(newInnerSelect.Where, newOuterSelect.Alias, outerKeys, innerKeys))
                        {
                            // outerKey needs to refer to the outer-scope's alias
                            var outerKey = outerKeys.Select(k => FieldMapper.Map(k, save.Alias, newOuterSelect.Alias));
                            // innerKey needs to refer to the new alias for the select with the new join
                            var innerKey = innerKeys.Select(k => FieldMapper.Map(k, joinedSelect.Alias, ((FieldExpression)k).Alias));
                            ProjectionExpression newProjection = new ProjectionExpression(joinedSelect, newProjector, proj.Aggregator);
                            return new ClientJoinExpression(newProjection, outerKey, innerKey);
                        }
                    }
                    else
                    {
                        bool saveJoin = this.canJoinOnClient;
                        this.canJoinOnClient = false;
                        var result = base.VisitProjection(proj);
                        this.canJoinOnClient = saveJoin;
                        return result;
                    }
                }
                else
                {
                    this.isTopLevel = false;
                }
                return base.VisitProjection(proj);
            }
            finally
            {
                this.currentSelect = save;
            }
        }
Пример #19
0
 protected override Expression VisitProjection(ProjectionExpression proj)
 {
     // treat these like scalar subqueries
     if ((proj.Projector is  FieldExpression) || this.forDebug)
     {
         this.Write("(");
         this.WriteLine(Indentation.Inner);
         this.Visit(proj.Select);
         this.Write(")");
         this.Indent(Indentation.Outer);
     }
     else
     {
         throw new NotSupportedException("Non-scalar projections cannot be translated to SQL.");
     }
     return proj;
 }
Пример #20
0
 protected virtual Expression VisitProjection(ProjectionExpression proj)
 {
     var select = (SelectExpression)this.Visit(proj.Select);
     var projector = this.Visit(proj.Projector);
     return this.UpdateProjection(proj, select, projector, proj.Aggregator);
 }
Пример #21
0
        protected virtual Expression GetInsertResult(IMappedEntity entity, Expression instance, LambdaExpression selector, Dictionary<MemberInfo, Expression> map)
        {
            var IdentifiableAlias = new IdentifiableAlias();
            var tex = new IdentifiableExpression(IdentifiableAlias, entity, this.mapping.GetTableName(entity));
            var aggregator = Aggregator.GetAggregator(selector.Body.Type, typeof(IEnumerable<>).MakeGenericType(selector.Body.Type));

            Expression where;
            DeclarationCommand genIdCommand = null;
            var generatedIds = this.mapping.GetMappedMembers(entity).Where(m => this.mapping.IsPrimaryKey(entity, m) && this.mapping.IsGenerated(entity, m)).ToList();
            if (generatedIds.Count > 0)
            {
                if (map == null || !generatedIds.Any(m => map.ContainsKey(m)))
                {
                    var localMap = new Dictionary<MemberInfo, Expression>();
                    genIdCommand = this.GetGeneratedIdCommand(entity, generatedIds.ToList(), localMap);
                    map = localMap;
                }

                // is this just a retrieval of one generated id member?
                var mex = selector.Body as MemberExpression;
                if (mex != null && this.mapping.IsPrimaryKey(entity, mex.Member) && this.mapping.IsGenerated(entity, mex.Member))
                {
                    if (genIdCommand != null)
                    {
                        // just use the select from the genIdCommand
                        return new ProjectionExpression(
                            genIdCommand.Source,
                            new FieldExpression(mex.Type, genIdCommand.Variables[0].QueryType, genIdCommand.Source.Alias, genIdCommand.Source.Fields[0].Name),
                            aggregator
                            );
                    }
                    else
                    {
                        IdentifiableAlias alias = new IdentifiableAlias();
                        var colType = this.GetFieldType(entity, mex.Member);
                        return new ProjectionExpression(
                            new SelectExpression(alias, new[] { new FieldDeclaration("", map[mex.Member], colType) }, null, null),
                            new FieldExpression(TypeHelper.GetMemberType(mex.Member), colType, alias, ""),
                            aggregator
                            );
                    }
                }

                where = generatedIds.Select((m, i) =>
                    this.GetMemberExpression(tex, entity, m).Equal(map[m])
                    ).Aggregate((x, y) => x.And(y));
            }
            else
            {
                where = this.GetIdentityCheck(tex, entity, instance);
            }

            Expression typeProjector = this.GetEntityExpression(tex, entity);
            Expression selection = DbExpressionReplacer.Replace(selector.Body, selector.Parameters[0], typeProjector);
            IdentifiableAlias newAlias = new IdentifiableAlias();
            var pc = FieldProjector.ProjectFields(this.translator.Linguist.Language, selection, null, newAlias, IdentifiableAlias);
            var pe = new ProjectionExpression(
                new SelectExpression(newAlias, pc.Fields, tex, where),
                pc.Projector,
                aggregator
                );

            if (genIdCommand != null)
            {
                return new BlockCommandExpression(genIdCommand, pe);
            }
            return pe;
        }
Пример #22
0
 protected virtual Expression VisitProjection(ProjectionExpression projection)
 {
     this.AddAlias(projection.Select.Alias);
     this.Write("Project(");
     this.WriteLine(Indentation.Inner);
     this.Write("@\"");
     this.Visit(projection.Select);
     this.Write("\",");
     this.WriteLine(Indentation.Same);
     this.Visit(projection.Projector);
     this.Write(",");
     this.WriteLine(Indentation.Same);
     this.Visit(projection.Aggregator);
     this.WriteLine(Indentation.Outer);
     this.Write(")");
     return projection;
 }
Пример #23
0
 private Expression BindFirst(Expression source, LambdaExpression predicate, string kind, bool isRoot)
 {
     ProjectionExpression projection = this.VisitSequence(source);
     Expression where = null;
     if (predicate != null)
     {
         this.map[predicate.Parameters[0]] = projection.Projector;
         where = this.Visit(predicate.Body);
     }
     bool isFirst = kind.StartsWith("First");
     bool isLast = kind.StartsWith("Last");
     Expression take = (isFirst || isLast) ? Expression.Constant(1) : null;
     if (take != null || where != null)
     {
         var alias = this.GetNextAlias();
         ProjectedFields pc = this.ProjectFields(projection.Projector, alias, projection.Select.Alias);
         projection = new ProjectionExpression(
             new SelectExpression(alias, pc.Fields, projection.Select, where, null, null, false, null, take, isLast),
             pc.Projector
             );
     }
     if (isRoot)
     {
         Type elementType = projection.Projector.Type;
         ParameterExpression p = Expression.Parameter(typeof(IEnumerable<>).MakeGenericType(elementType), "p");
         LambdaExpression gator = Expression.Lambda(Expression.Call(typeof(Enumerable), kind, new Type[] { elementType }, p), p);
         return new ProjectionExpression(projection.Select, projection.Projector, gator);
     }
     return projection;
 }
Пример #24
0
        public override Expression GetMemberExpression(Expression root, IMappedEntity entity, MemberInfo member)
        {
            if (this.mapping.IsAssociationRelationship(entity, member))
            {
                var relatedEntity = this.mapping.GetRelatedEntity(entity, member);
                ProjectionExpression projection = this.GetQueryExpression(relatedEntity);

                // make where clause for joining back to 'root'
                var declaredTypeMembers = this.mapping.GetAssociationKeyMembers(entity, member).ToList();
                var associatedMembers = this.mapping.GetAssociationRelatedKeyMembers(entity, member).ToList();

                Expression where = null;
                for (int i = 0, n = associatedMembers.Count; i < n; i++)
                {
                    Expression equal =
                        this.GetMemberExpression(projection.Projector, relatedEntity, associatedMembers[i]).Equal(
                            this.GetMemberExpression(root, entity, declaredTypeMembers[i])
                        );
                    where = (where != null) ? where.And(equal) : equal;
                }

                IdentifiableAlias newAlias = new IdentifiableAlias();
                var pc = FieldProjector.ProjectFields(this.translator.Linguist.Language, projection.Projector, null, newAlias, projection.Select.Alias);

                LambdaExpression aggregator = Aggregator.GetAggregator(TypeHelper.GetMemberType(member), typeof(IEnumerable<>).MakeGenericType(pc.Projector.Type));
                var result = new ProjectionExpression(
                    new SelectExpression(newAlias, pc.Fields, projection.Select, where),
                    pc.Projector, aggregator
                    );

                return this.translator.Police.ApplyPolicy(result, member);
            }
            else
            {
                AliasedExpression aliasedRoot = root as AliasedExpression;
                if (aliasedRoot != null && this.mapping.IsField(entity, member))
                {
                    return new FieldExpression(TypeHelper.GetMemberType(member),
                        this.GetFieldType(entity, member),
                        aliasedRoot.Alias,
                        this.mapping.GetFieldName(entity, member));
                }
                return QueryBinder.BindMember(root, member);
            }
        }
Пример #25
0
        protected override Expression ExecuteProjection(ProjectionExpression projection, QueryCommand command, Expression[] values)
        {
            var saveScope = this.Scope;
            ParameterExpression reader = Expression.Parameter(typeof(FieldReader), "r" + nReaders++);
            this.Scope = new BuilderScope(this.Scope, reader, projection.Select.Alias, projection.Select.Fields)
            {
                UseOrdinalMapping = false // orient cannot guarantee ordinally mapped results - must map by name
            };

            var projector = RedirectProjector(projection.Projector, reader, true);

            this.Scope = saveScope;

            var entity = EntityFinder.Find(projection.Projector);

            if (entity != null && entity.EntityType == typeof(_Thing))
            {
                entity = new OMappingEntity(typeof(IIdentifiable),_repoType);
            }

            string methExecute = "Execute";

            // call low-level execute directly on supplied DbQueryProvider
            Expression result = Expression.Call(this.Executor, methExecute, new Type[] { projector.Body.Type },
                Expression.Constant(command),
                projector,
                Expression.Constant(entity, typeof(MappingEntity)),
                Expression.NewArrayInit(typeof(object), values)
                );

            if (projection.Aggregator != null)
            {
                if (projector.ReturnType != projection.Aggregator.Parameters[0].Type.GetGenericArguments()[0])
                {
                    // we probably swaped out an Identifiable type for IIdentifiable, so we need to rebuild the projection
                    // using the interface, otherwise we'll get cast failures downstream
                    projection = new ProjectionExpression(
                        projection.Select,
                        projector,
                        Aggregator.GetAggregator(projector.ReturnType,
                        projection.Aggregator.Parameters[0].Type.GetGenericTypeDefinition().MakeGenericType(projector.ReturnType)));
                }
                // apply aggregator
                result = DbExpressionReplacer.Replace(projection.Aggregator.Body, projection.Aggregator.Parameters[0], result);
            }
            return result;
        }