示例#1
0
        public virtual ProjectionExpression AddOuterJoinTest(ProjectionExpression proj)
        {
            var test   = this.GetOuterJoinTest(proj.Select);
            var select = proj.Select;
            ColumnExpression testCol = null;

            // look to see if test expression exists in columns already
            foreach (var col in select.Columns)
            {
                if (test.Equals(col.Expression))
                {
                    var colType = this.TypeSystem.GetColumnType(test.Type);
                    testCol = new ColumnExpression(test.Type, colType, select.Alias, col.Name);
                    break;
                }
            }
            if (testCol == null)
            {
                // add expression to projection
                testCol = test as ColumnExpression;
                string colName = (testCol != null) ? testCol.Name : "Test";
                colName = proj.Select.Columns.GetAvailableColumnName(colName);
                var colType = this.TypeSystem.GetColumnType(test.Type);
                select  = select.AddColumn(new ColumnDeclaration(colName, test, colType));
                testCol = new ColumnExpression(test.Type, colType, select.Alias, colName);
            }
            var newProjector = new OuterJoinedExpression(testCol, proj.Projector);

            return(new ProjectionExpression(select, newProjector, proj.Aggregator));
        }
示例#2
0
        public static ProjectionExpression AddOuterJoinTest(this ProjectionExpression proj, QueryLanguage language, Expression expression)
        {
            string           colName      = proj.Select.Columns.GetAvailableColumnName("Test");
            var              colType      = language.TypeSystem.GetColumnType(expression.Type);
            SelectExpression newSource    = proj.Select.AddColumn(new ColumnDeclaration(colName, expression, colType));
            Expression       newProjector =
                new OuterJoinedExpression(
                    new ColumnExpression(expression.Type, colType, newSource.Alias, colName),
                    proj.Projector
                    );

            return(new ProjectionExpression(newSource, newProjector, proj.Aggregator));
        }
        protected override Expression VisitOuterJoined(OuterJoinedExpression outer)
        {
            Expression          expr   = this.Visit(outer.Expression);
            ColumnExpression    column = (ColumnExpression)outer.Test;
            ParameterExpression reader;
            int iOrdinal;

            if (this.scope.TryGetValue(column, out reader, out iOrdinal))
            {
                return(Expression.Condition(
                           Expression.Call(reader, "IsDbNull", null, Expression.Constant(iOrdinal)),
                           Expression.Constant(TypeHelper.GetDefault(outer.Type), outer.Type),
                           expr
                           ));
            }
            return(expr);
        }
        protected Expression Compare(BinaryExpression bop)
        {
            var e1 = this.SkipConvert(bop.Left);
            var e2 = this.SkipConvert(bop.Right);

            OuterJoinedExpression oj1 = e1 as OuterJoinedExpression;
            OuterJoinedExpression oj2 = e2 as OuterJoinedExpression;

            EntityExpression entity1 = oj1 != null ? oj1.Expression as EntityExpression : e1 as EntityExpression;
            EntityExpression entity2 = oj2 != null ? oj2.Expression as EntityExpression : e2 as EntityExpression;

            bool negate = bop.NodeType == ExpressionType.NotEqual;

            // check for outer-joined entity comparing against null. These are special because outer joins have
            // a test expression specifically desgined to be tested against null to determine if the joined side exists.
            if (oj1 != null && e2.NodeType == ExpressionType.Constant && ((ConstantExpression)e2).Value == null)
            {
                return(MakeIsNull(oj1.Test, negate));
            }
            else if (oj2 != null && e1.NodeType == ExpressionType.Constant && ((ConstantExpression)e1).Value == null)
            {
                return(MakeIsNull(oj2.Test, negate));
            }

            // if either side is an entity construction expression then compare using its primary key members
            if (entity1 != null)
            {
                return(this.MakePredicate(e1, e2, this.mapping.GetPrimaryKeyMembers(entity1.Entity), negate));
            }
            else if (entity2 != null)
            {
                return(this.MakePredicate(e1, e2, this.mapping.GetPrimaryKeyMembers(entity2.Entity), negate));
            }

            // check for comparison of user constructed type projections
            var dm1 = this.GetDefinedMembers(e1);
            var dm2 = this.GetDefinedMembers(e2);

            if (dm1 == null && dm2 == null)
            {
                // neither are constructed types
                return(bop);
            }

            if (dm1 != null && dm2 != null)
            {
                // both are constructed types, so they'd better have the same members declared
                HashSet <string> names1 = new HashSet <string>(dm1.Select(m => m.Name));
                HashSet <string> names2 = new HashSet <string>(dm2.Select(m => m.Name));
                if (names1.IsSubsetOf(names2) && names2.IsSubsetOf(names1))
                {
                    return(MakePredicate(e1, e2, dm1, negate));
                }
            }
            else if (dm1 != null)
            {
                return(MakePredicate(e1, e2, dm1, negate));
            }
            else if (dm2 != null)
            {
                return(MakePredicate(e1, e2, dm2, negate));
            }

            throw new InvalidOperationException("Cannot compare two constructed types with different sets of members assigned.");
        }