It's been really usefull this documentation. Thanks and great job.
As far I've been able to figure out, I've created a ResultOperator (
: SequenceTypePreservingResultOperatorBase) and a re-linq hook (
: ResultOperatorExpressionNodeBase) and finally register it on re-linq.
I've created my custom Linq provider using re-linq in order to get information from a server. So, I provide some util methods (
MetaInfoKey bellow)
in order to create Expressions in order to avoid work to the user. For example:
this.backend.Query<Backend.Domain.FollowUpActivity>()
.GroupBy(LinqTreeExtensions.Query<Backend.Domain.FollowUpActivity>(f => f).MetaInfoKey<Backend.Domain.FollowUpActivity, string>("Key"))
.Select(g => new { Value = g.Key, Count = g.Count() });
I need these custom made expressions are `compatible` with "Linq over collections" provider.
Shortly, the expression is generating
MetaInfoKey
is
:
{f => Convert(f.Metainfos.Where(m => (m.Key == "Key")).SingleOrEmpty().Value)}
In order to build it I do:
ParameterExpression entityParameter = expr.Parameters.First();
ParameterExpression metaInfoParameterExpression = Expression.Parameter(collGenericType, "m");
MemberExpression collectionMemberExpression = Expression.Property(entityParameter, collectionPropertyInfo);
MethodInfo whereMethod = typeof(Enumerable).GetMethods().Where(m => m.Name.Equals("Where") && m.GetParameters().Length == 2).First().MakeGenericMethod(collGenericType);
MethodInfo singleMethod = typeof(LinqTreeExtensions).GetMethods().Where(m => m.Name.Equals("SingleOrEmpty") && m.GetParameters().Length == 1).First().MakeGenericMethod(collGenericType);
LambdaExpression innerCondition = Expression.Lambda(
Expression.GetDelegateType(collGenericType, typeof(bool)),
Expression.Equal(
Expression.Property(metaInfoParameterExpression, "Key"),
Expression.Constant(field)
),
metaInfoParameterExpression
);
MethodCallExpression whereCallExpression = Expression.Call(whereMethod, collectionMemberExpression, innerCondition);
MethodCallExpression singleCallExpression = Expression.Call(singleMethod, whereCallExpression);
MemberExpression memberExpression = Expression.Property(singleCallExpression, "Value");
UnaryExpression convertExpression = Expression.Convert(memberExpression, typeof(TKeyType));
Expression<Func<TElementType, TKeyType>> lambdaExpression = Expression.Lambda<Func<TElementType, TKeyType>>(convertExpression, entityParameter);
return lambdaExpression;
The first problem I'm facing up is how to implement the
SingleOrEmpty
extension method:
public static IQueryable<TSource> SingleOrEmpty<TSource>(this IQueryable<TSource> source)
{
return source.Provider.CreateQuery<TSource>(
Expression.Call(
((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
source.Expression
)
);
}
I'm guessing it's building a CallMethodExpression, but where's the implementation? Remember that it's to be performed over Linq-Collection as well...
I hope I've explained so well.