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."); }
protected override Expression VisitEntity(EntityExpression entity) { return(this.Visit(entity.Expression)); }