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