Search code examples
c#linqentity-frameworklinq-to-entitiespredicate

Passing a parameter to a linq predicate


I want to write code like the following -

    public IQueryable<Invoice> InvoiceFilterForMonthAndYear(DateTime? monthAndYear = null)
    {
        var invoices = _invoices.Where(MonthAndYearPredicate(monthAndYear);
        return invoices;
    }

    private bool MonthAndYearPredicate(Invoice invoice, DateTime? monthAndYear)
    {
        //code to check if the invoice start or end dates is from the falls in the month I am checking for
    }

But I can't use a predicate like that because the predicate expects just one parameter.

I know I could write a Where clause in InvoiceFilterForMonthAndYear to do the work, but I want to put the logic for the comparison into its own method.


Solution

  • It works if your method for comparison returns an expression:

    private Expression<Func<Invoice,bool>> MonthAndYearPredicate(
        DateTime? monthAndYear)
    {
        return i => i.StartDate >= monthAndYear; // or whatever
    }
    

    To be called like in your example:

    var invoices = _invoices.Where(MonthAndYearPredicate(monthAndYear));
    

    Or you could extract the logic into an extension method of IQueryable<Invoice>:

    public static class QueryExtensions
    {
        public static IQueryable<Invoice> WhereMonthAndYear(
            this IQueryable<Invoice> query, DateTime? monthAndYear)
        {
            return query.Where(i => i.StartDate >= monthAndYear); // or whatever
        }
    }
    

    To be called like so:

    var invoices = _invoices.WhereMonthAndYear(monthAndYear);
    

    Keep in mind that in both cases you have to use valid LINQ-to-Entities expressions that EF can translate into SQL. It only makes the expressions reusable for different queries but does not extend its capabilities.