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)); }
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."); }