Is it possible to create a "meta-predicate" by writing a a function that takes 2 (or 4 if necessary) lambdas which represent the left and right side properties (operands) and have it generate an predicate. Something like the following code sample:
public Expression<Func<Something,bool>> StringEquals<Something>(Expression<Something> leftOperand, Expression<Something> leftOperandSelector){
return (rightOperandSelector, leftOperandSelector) => (
(rightOperandSelector == leftOperandSelector)
|| (
string.IsNullOrEmpty(rightOperandSelector) &&
string.IsNullOrEmpty(leftOperandSelector)
)
);
}
OR:
public Expression<Func<Something,bool>> DatesActive<Something>(Expression<Something> startDateOperandSelector, Expression<Something> endDateOperandSelector){
return (startDateOperandSelector, endDateOperandSelector) => (
(startDatePropertySelector >= DateTime.Now)
&& (endDatePropertySelector <= DateTime.Now)
);
}
Where SomeStringProperty for each side or startDatePropertySelector or endDatePropertySelector is defined by a lambda? I have not figured out how to dynamically pass the Operand of the predicate expression.
Ideally I would like to be able to inline it like this:
return new Expression<Func<Request,bool>>[]{
r => (r.Id != request.Id) && (!r.Reviewed),
StringEquals(r => r.VendorName, request=>request.VendorName),
NotExpired(r => r.ContractStart, request=>request.ContractEnd),
...
};
*Does someone have an idea on the best way to approach this? My interest is in creating "meta"-expressions for easy use where I am using the same expression repeatedly over multiple properties. Concrete example is given just for reference/explanation. Very open to knowing if this is silly and if there is a better approach, happy to learn. *
More background below if desired.
Background: After a simpler form of this Expression was in place I was forced to refactor to handle the fact that EntityFramework doesn't treat equality how you would expect in that instead of interpreting C# like the following:
(rightSide.SomeStringProperty == leftSide.SomeStringProperty)
as a two part SQL expression like this
(
(rightSide.SomeStringProperty IS NULL AND leftSide.SomeStringProperty IS NULL)
OR (rightSide.SomeStringProperty = leftSide.SomeStringProperty)
)
it more literally tranlates it as:
(rightSide.SomeStringProperty = leftSide.SomeStringProperty)
which of course will not return values for where both sides are null. Apparently this has been corrected in EF6 (Correction: @Slauma points out this is available in EF5 via the UseCSharpNullComparisonBehavior. I am using EF4 and cannot upgrade for this release.)
I want to avoid more repetitive code like the following:
var where = new Expression<Func<Request,bool>>[]{
r => (r.Id != request.Id) && (!r.Reviewed)
&& (
(r.Address == request.Address)
|| (string.IsNullOrEmpty(r.Address) && string.IsNullOrEmpty(request.Address))
)
&& (
(r.City == request.City)
|| (string.IsNullOrEmpty(r.City) && string.IsNullOrEmpty(request.City))
)
&& (
(r.Province == request.Province)
|| (string.IsNullOrEmpty(r.Province) && string.IsNullOrEmpty(request.Province))
)
&& (
(r.PostalCode == request.PostalCode)
|| (string.IsNullOrEmpty(r.PostalCode) && string.IsNullOrEmpty(request.PostalCode))
)
&& (
(r.Website == request.Website)
|| (string.IsNullOrEmpty(r.Website) && string.IsNullOrEmpty(request.Website))
)
};