I am trying to create my own custom operation which I can use in the database to find rows which are affected by a change in a value.
Im looking at Jon Skeets between operator example here: LINQ Between Operator but im having trouble as my operation contains multiple parameter inputs
public static IQueryable<TSource> LeavingRange<TSource, TKey>(this IQueryable<TSource> source,
Expression<Func<TSource, TKey>> lowKeySelector,
Expression<Func<TSource, TKey>> highKeySelector,
Nullable<TKey> oldValue,
Nullable<TKey> newValue)
where TKey : struct, IComparable<TKey>
As you can see I have 2 selectors, however I'm not too sure how to combine these correctly into the parameters for my Expression.Lambda
call. I have tried just putting the parameters from both input expressions into the lambda as parameters but i think im missing something.
Expression.Lambda<Func<TSource, bool>>(isLeavingRange, lowKeySelector.Parameters[0], highKeySelector.Parameters[0]);
Doing this gives the following error:
Incorrect number of parameters supplied for lambda declaration
What is the correct way to combine the input parameters when constructing a Lambda?
Supporting Info
My full code is below, but I think the relevant bits are the two selectors and the Expression.Lambda
call
public static IQueryable<TSource> LeavingRange<TSource, TKey>(this IQueryable<TSource> source,
Expression<Func<TSource, TKey>> lowKeySelector,
Expression<Func<TSource, TKey>> highKeySelector,
Nullable<TKey> oldValue,
Nullable<TKey> newValue)
where TKey : struct, IComparable<TKey>
{
Expression lowKey = Expression.Invoke(lowKeySelector, lowKeySelector.Parameters.ToArray());
Expression highKey = Expression.Invoke(highKeySelector, highKeySelector.Parameters.ToArray());
//is oldValue null which means it cant possibly be leaving
var oldValueIsNotNull = Expression.NotEqual(Expression.Constant(oldValue, typeof(Nullable<TKey>)), Expression.Constant(null, typeof(Nullable<TKey>)));
var newValueIsNull = Expression.Equal(Expression.Constant(newValue, typeof(Nullable<TKey>)), Expression.Constant(null, typeof(Nullable<TKey>)));
var newValueIsNotNull = Expression.Not(newValueIsNull);
var oldValueIsBetweenRange = Between(Expression.Convert(Expression.Constant(oldValue), typeof(TKey)), lowKey, highKey);
var newValueIsNotBetweenRange = Expression.Not(Between(Expression.Convert(Expression.Constant(newValue), typeof(TKey)), lowKey, highKey));
//IE leaving because its going from in the range to null
var newValueIsNullAndOldValueIsBetweenRange = Expression.AndAlso(newValueIsNull, oldValueIsBetweenRange);
var oldValueIsInRangeAndNewValueIsNot = Expression.AndAlso(newValueIsNotNull, Expression.AndAlso(oldValueIsBetweenRange, newValueIsNotBetweenRange));
var isLeavingRange = Expression.AndAlso(oldValueIsNotNull, Expression.Or(newValueIsNullAndOldValueIsBetweenRange, oldValueIsInRangeAndNewValueIsNot));
var leavingRange = Expression.Lambda<Func<TSource, bool>>(isLeavingRange, lowKeySelector.Parameters[0], highKeySelector.Parameters[0]);
return source.Where(leavingRange);
}