Implement by leveraging the ContainsResultOperator introduced in COMMONS-1313
The new KeySelector/ElementSelector expressions correspond KeySelector.ResolvedExpression and ElementSelector.ResolvedExpression.
Constructs a LambdaExpression that finds how to extract a specific piece of data (QuerySourceReferenceExpression) from a complex expression.
Examples:
AccessorFindingExpressionTreeVisitor.FindAccessor ([s], [s]) -> input => input
AccessorFindingExpressionTreeVisitor.FindAccessor ([s], new {x = [s], y = [sd]}) -> input => input.x
AccessorFindingExpressionTreeVisitor.FindAccessor ([sector], new { x = [s], y = new { a = [sd], b = [sector] } }) -> input => input.y.b
Suggested implementation:
foreach (memberbinding) { push memberbinding.Member; VisitExpression (memberBinding.Expression); pop memberbinding.Member; }
if (input == searchedExpression) { return MakeMemberAccessChain (members); } else if (input.NodeType != New/MemberInit) throw ...; else return base.VisitExpression (expression);
class ExecuteInMemoryData { public object CurrentValue { get; private set; } public Expression CurrentExpression { get; private set; } } public abstract ResultOperatorBase { public abstract ExecuteInMemoryData ExecuteInMemory (ExecuteInMemoryData input); }
Implementation is similar to current ExecuteInMemory method, with the difference that every result operator gets an Expression matching the input data and returns an Expression matching the output data. For example, for Count:
public override ExecuteInMemoryData ExecuteInMemory (ExecuteInMemoryData input) { ArgumentUtility.CheckNotNull ("input", input); return InvokeGenericExecuteForEnumerable<int> (input, ExecuteInMemory); } public ExecuteInMemoryData ExecuteInMemory<T> (ExecuteInMemoryData input) { ArgumentUtility.CheckNotNull ("input", input); var enumerableInput = (IEnumerable<T>) input.CurrentValue; var result = enumerableInput.Count (): var resultExpression = Resolve<IEnumerable<T>, int> (input.CurrentExpression, input => input.Count()); return new ExecuteInMemoryData (result, resultExpression); } protected Expression Resolve<TSource, TResult> (Expression inputExpression, Expression<Func<TSource, TResult>> expressionToBeResolved) { return ReplacingExpressionTreeVisitor.Replace (expressionToBeResolved.Parameters[0], inputExpression, expressionToBeResolved.Body); }
Implement for all trivial result operators, do not implement for GroupResultOperator.
Create a ContainsObjectExpressionNode, which, in its CreateResultOperator method creates a ContainsResultOperator with the argument passed to the ContainsObject method.
Ie.
from o in QueryFactory.CreateLinqQuery<Order>() where o.OrderItems.ContainsObject (item) select o
becomes
from o in ... where { from gen in o.OrderItems select gen => Contains (item) } select o
automatically via the ContainsObjectExpressionNode.
The new parser must be registered in DomainObjectQueryable's ctor.