コード例 #1
0
    public override Expression?Visit(Expression?expression)
    {
        if (this.candidates.Contains(expression !))
        {
            if (expression is ColumnExpression column)
            {
                if (!projectTrivialColumns)
                {
                    return(expression);
                }

                if (this.map.TryGetValue(column, out var mapped))
                {
                    return(mapped);
                }

                mapped           = generator.MapColumn(column).GetReference(newAlias);
                this.map[column] = mapped;
                return(mapped);
            }
            else
            {
                if (expression !.Type.UnNullify().IsEnum)
                {
                    var convert = expression.TryConvert(expression.Type.IsNullable() ? typeof(int?) : typeof(int));

                    return(generator.NewColumn(convert).GetReference(newAlias).TryConvert(expression.Type));
                }
コード例 #2
0
    protected internal override Expression VisitProjection(ProjectionExpression proj)
    {
        if (currentSource == null)
        {
            currentSource = WithoutOrder(proj.Select);

            Expression projector = this.Visit(proj.Projector);

            if (projector != proj.Projector)
            {
                proj = new ProjectionExpression(proj.Select, projector, proj.UniqueFunction, proj.Type);
            }

            currentSource = null;
            return(proj);
        }
        else
        {
            HashSet <ColumnExpression> columns = ExternalColumnGatherer.Gatherer(proj, currentSource.Alias);

            if (columns.Count == 0)
            {
                Expression projector = Visit(proj.Projector);

                ConstantExpression key   = Expression.Constant(0);
                Type            kvpType  = typeof(KeyValuePair <,>).MakeGenericType(key.Type, projector.Type);
                ConstructorInfo ciKVP    = kvpType.GetConstructor(new[] { key.Type, projector.Type }) !;
                Type            projType = proj.UniqueFunction == null ? typeof(IEnumerable <>).MakeGenericType(kvpType) : kvpType;

                var childProj = new ProjectionExpression(proj.Select,
                                                         Expression.New(ciKVP, key, projector), proj.UniqueFunction, projType);

                return(new ChildProjectionExpression(childProj,
                                                     Expression.Constant(0), inMList != null, inMList ?? proj.Type, new LookupToken()));
            }
            else
            {
                SelectExpression external;
                IEnumerable <ColumnExpression> externalColumns;

                if (!IsKey(currentSource, columns))
                {
                    Alias           aliasDistinct     = aliasGenerator.GetUniqueAlias(currentSource.Alias.Name + "D");
                    ColumnGenerator generatorDistinct = new ColumnGenerator();

                    List <ColumnDeclaration> columnDistinct = columns.Select(ce => generatorDistinct.MapColumn(ce)).ToList();
                    external = new SelectExpression(aliasDistinct, true, null, columnDistinct, currentSource, null, null, null, 0);


                    Dictionary <ColumnExpression, ColumnExpression> distinctReplacements = columnDistinct.ToDictionary(
                        cd => (ColumnExpression)cd.Expression,
                        cd => cd.GetReference(aliasDistinct));

                    proj = (ProjectionExpression)ColumnReplacer.Replace(proj, distinctReplacements);

                    externalColumns = distinctReplacements.Values.ToHashSet();
                }
                else
                {
                    external        = currentSource;
                    externalColumns = columns;
                }

                ColumnGenerator          generatorSM       = new ColumnGenerator();
                List <ColumnDeclaration> columnsSMExternal = externalColumns.Select(ce => generatorSM.MapColumn(ce)).ToList();
                List <ColumnDeclaration> columnsSMInternal = proj.Select.Columns.Select(cd => generatorSM.MapColumn(cd.GetReference(proj.Select.Alias))).ToList();

                SelectExpression @internal = ExtractOrders(proj.Select, out List <OrderExpression>?innerOrders);

                Alias            aliasSM    = aliasGenerator.GetUniqueAlias(@internal.Alias.Name + "SM");
                SelectExpression selectMany = new SelectExpression(aliasSM, false, null, columnsSMExternal.Concat(columnsSMInternal),
                                                                   new JoinExpression(JoinType.CrossApply,
                                                                                      external,
                                                                                      @internal, null), null, innerOrders, null, 0);

                SelectExpression old = currentSource;
                currentSource = WithoutOrder(selectMany);

                var selectManyReplacements = selectMany.Columns.ToDictionary(
                    cd => (ColumnExpression)cd.Expression,
                    cd => cd.GetReference(aliasSM));

                Expression projector = ColumnReplacer.Replace(proj.Projector, selectManyReplacements);

                projector = Visit(projector);

                currentSource = old;

                Expression      key      = TupleReflection.TupleChainConstructor(columnsSMExternal.Select(cd => MakeEquatable(cd.GetReference(aliasSM))));
                Type            kvpType  = typeof(KeyValuePair <,>).MakeGenericType(key.Type, projector.Type);
                ConstructorInfo ciKVP    = kvpType.GetConstructor(new[] { key.Type, projector.Type }) !;
                Type            projType = proj.UniqueFunction == null ? typeof(IEnumerable <>).MakeGenericType(kvpType) : kvpType;

                var childProj = new ProjectionExpression(selectMany,
                                                         Expression.New(ciKVP, key, projector), proj.UniqueFunction, projType);

                return(new ChildProjectionExpression(childProj,
                                                     TupleReflection.TupleChainConstructor(columns.Select(a => MakeEquatable(a))), inMList != null, inMList ?? proj.Type, new LookupToken()));
            }
        }
    }