// We would usually get NULL if one of our inner member expresions was null. // However, it's possible a method call will convert the null value from the failed join into a non-null value. // This could be optimized by actually checking what the method does. For example StartsWith("s") would leave null as null and would still allow us to inner join. //protected override Expression VisitMethodCallExpression(MethodCallExpression expression) //{ // Expression result = base.VisitMethodCallExpression(expression); // return result; //} protected override Expression VisitMemberExpression(MemberExpression expression) { // The member expression we're visiting might be on the end of a variety of things, such as: // a.B // a.B.C // (a.B ?? a.C).D // I'm not sure what processing re-linq does to strange member expressions. // TODO: I suspect this code doesn't add the right joins for the last case. _memberExpressionDepth++; var result = base.VisitMemberExpression(expression); _memberExpressionDepth--; ExpressionValues values = _values.Pop().Operation(pvs => pvs.MemberAccess(expression.Type)); if (_isEntityDecider.IsEntity(expression.Type)) { // Don't add joins for things like a.B == a.C where B and C are entities. // We only need to join B when there's something like a.B.D. // TODO: Add an exception for the Id property. if (_memberExpressionDepth > 0) { AddJoin(expression); } string key = ExpressionKeyVisitor.Visit(expression, null); values.MemberExpressionValuesIfEmptyOuterJoined[key] = PossibleValueSet.CreateNull(expression.Type); } SetResultValues(values); return(result); }
// We would usually get NULL if one of our inner member expressions was null. // However, it's possible a method call will convert the null value from the failed join into a non-null value. // This could be optimized by actually checking what the method does. For example StartsWith("s") would leave null as null and would still allow us to inner join. //protected override Expression VisitMethodCall(MethodCallExpression expression) //{ // Expression result = base.VisitMethodCall(expression); // return result; //} protected override Expression VisitMember(MemberExpression expression) { // The member expression we're visiting might be on the end of a variety of things, such as: // a.B // a.B.C // (a.B ?? a.C).D // I'm not sure what processing re-linq does to strange member expressions. // TODO: I suspect this code doesn't add the right joins for the last case. // A static member expression such as DateTime.Now has a null Expression. if (expression.Expression == null) { // A static member call is never a join, and it is not an instance member access either: leave // the current value on stack, untouched. return(base.VisitMember(expression)); } var isIdentifier = _isEntityDecider.IsIdentifier( expression.Expression.Type, expression.Member.Name); if (!isIdentifier) { _memberExpressionDepth++; } var result = base.VisitMember(expression); if (!isIdentifier) { _memberExpressionDepth--; } ExpressionValues values = _values.Pop().Operation(pvs => pvs.MemberAccess(expression.Type)); if (_isEntityDecider.IsEntity(expression.Type)) { // Don't add joins for things like a.B == a.C where B and C are entities. // We only need to join B when there's something like a.B.D. var key = ExpressionKeyVisitor.Visit(expression, null); if (_memberExpressionDepth > 0 && _joiner.CanAddJoin(expression)) { result = _joiner.AddJoin(result, key); } values.MemberExpressionValuesIfEmptyOuterJoined[key] = PossibleValueSet.CreateNull(expression.Type); } SetResultValues(values); return(result); }