When comparing compound values for inequality, member comparisons must be combined using "or", but they are combined using "and":
where new { X = 1, Y = 2 } != new { X = o.Property1, Y = o.Property2 }
should be equivalent to:
where 1 != o.Property1 || 2 != o.Property2
but is interepreted as:
where 1 != o.Property1 && 2 != o.Property2
Implementation notes: ResolvingExpressionVisitor.VisitBinaryExpression should decide whether to use AndAlso or OrElse.
Currently, if a SQL transformer inserts an invocation-of-lambda expression pattern into a Where condition, the Predicate semantics is propagated to the lambda parameters, which leads to strange error messages. Improve by simply throwing on such expressions (or by handling the expressions in the correct way, ignoring lambda parameters and invocation arguments and applying predicate semantics only to the lambda body).
PartialEvaluatingExpressionTreeVisitor breaks while compiling lambda expression which has nested member access and upper member is null.
for example : Property.NestedProperty.Value == something
if Property == null (or NestedProperty == null) EvaluateSubtree will explode.
Here is a fix which works for me:
protected Expression EvaluateSubtree(Expression subtree) { ArgumentUtility.CheckNotNull("subtree", subtree); if (subtree.NodeType == ExpressionType.Constant) { var constantExpression = (ConstantExpression)subtree; var valueAsIQueryable = constantExpression.Value as IQueryable; if (valueAsIQueryable != null && valueAsIQueryable.Expression != constantExpression) return valueAsIQueryable.Expression; return constantExpression; } else if (subtree.NodeType == ExpressionType.MemberAccess && subtree is MemberExpression) { var me = (MemberExpression)subtree; if (me.Expression is MemberExpression) { var smb = (MemberExpression)me.Expression; Expression<Func<object>> outerLambda = Expression.Lambda<Func<object>>(Expression.Convert(smb, typeof(object))); object nullValue = outerLambda.Compile()(); if (nullValue == null) return Expression.Constant(null, subtree.Type); } } Expression<Func<object>> lambdaWithoutParameters = Expression.Lambda<Func<object>>(Expression.Convert(subtree, typeof(object))); object value = lambdaWithoutParameters.Compile()(); return Expression.Constant(value, subtree.Type); }
I've added a check for nested member evaluation and returned constant null if member is null.
While this is not entirely correct, since this part of lambda expression has purged evaluation shortcutting and this is consistent with sql behavior, I think this is accepted behavior.
You can improve this patch by recursively evaluating member expressions to see if some other property is not null.
For example if you have
Property.FirstNestedProperty.SecondNestedProperty.ThirdNestedProperty.Value
Regards,
Rikard
The UnionResultOperator currently pretends that it don't change the structure of the item sequence, passing through the incoming ItemExpression in its GetOutputDataInfo method. However, that's not correct, as the outgoing items may also come from a second source.
This manifests if Union is followed by an additional result operator. E.g.:
(from c in Cooks select c) .Union (OtherCooks) .Any (c2 => c2.IsFullTimeCook)
Currently, the AnyResultOperator's simplified predicate will reference the "c" from the MainFromClause. Which is wrong, since that specific item might also come from the OtherCooks collection. This should be changed so that the Any operator references the UnionResultOperator as a query source.
(IntersectResultOperator and ExceptResultOperator on the other hand should not be changed because they behave more like Take or Distinct, they are filtering the incoming sequence, so any outgoing item stems from that incoming sequence.)
IDictionary.Contains (and probably most implementations, such as Hashtable.Contains) have a different semantics than ICollection.Contains: they search for the key, not the value.
Therefore, ContainsExpressionNode should not handle IDictionary.Contains (and implementations).
Currently, when partial evaluation encounters an expression that throws an exception when executed in memory, the exception is propagated to the caller, and query parsing stops.
As an example, consider the following query:
string nullValue = null; var query = from c in Cooks where nullValue != null && nullValue.Length == c.ID select c;
Since c.ID cannot be evaluated, re-linq evaluates nullValue != null and nullValue.Length separately; the latter causes a NullReferenceException to be thrown.
It is desirable for partial evaluation to cope with such exceptions and optionally let the back-end decide how to deal with the exception. Therefore, implement the following fix:
The PartialEvaluationExceptionExpression reduces itself (when calling ExtensionExpression.Reduce) to the evaluated child expression. This enables back-ends not explicitly dealing with PartialEvaluationExceptionExpressions to just ignore the exception. Back-ends that want to deal with the exception can implement IPartialEvaluationExceptionExpressionVisitor.
As a result, back-ends unaware of the PartialEvaluationExceptionExpression should behave as if they received the following evaluated query from the front-end (as long as they support ExtensionExpressions):
from c in Cooks where false && null.Length == c.ID select c