10

I have a WhereFilter property in a base class which is as follows:

public virtual Expression<Func<CustomerCustomerType, bool>> WhereFilter
{
    get { return null; }
}

When it is overridden I want to return something else instead of null so I can use predicatebuilder extension And (from LinqKit) so I can write my code as follows:

public override Expression<Func<CustomerCustomerType, bool>> WhereFilter
{
    get { return base.WhereFilter.And(x => x.CustomerID == 1); }
}

But this gives error as WhereFilter is null (Object reference not set to an instance of an object).

Currently I am writing as:

public override Expression<Func<CustomerCustomerType, bool>> WhereFilter
{
    get { return x => x.CustomerID == 1; }
}

So when there is another child class overriding this, the base class property will be lost.

Any way to resolve this? In sql what I did was use a dummy where 1=1 thingy, can this be done similarly here in linq?

Umair
  • 4,864
  • 3
  • 28
  • 47

4 Answers4

21

LINQ's equivalent of the SQL's 1=1 "thingy" is a predicate that always returns true:

x => true

Change your default method as follows:

public virtual Expression<Func<CustomerCustomerType, bool>> WhereFilter
{
    get { return x=>true; }
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • I am getting this error after using this: The parameter 'x' was not bound in the specified LINQ to Entities query expression. – Umair Sep 03 '13 at 17:52
  • @MuhammadUmair This may be due to the use of `x` in other places. Try replacing with `get { return _ignored_parameter_ => true; }` and see if this fixes things for you. – Sergey Kalinichenko Sep 03 '13 at 18:03
  • @MuhammadUmair Check out [this article](http://blogs.msdn.com/b/meek/archive/2008/05/02/linq-to-entities-combining-predicates.aspx) for information that may be relevant to what you are doing. – Sergey Kalinichenko Sep 03 '13 at 18:05
  • giving it any name causes the same error, it actually generates this linq: c => (c.CategoryName.StartsWith("C") AndAlso Invoke(xyyyy => (True AndAlso Invoke(c => (c.CategoryID > 2), xyyyy)), c)) – Umair Sep 03 '13 at 18:17
  • 1
    @MuhammadUmair This is very likely a PB-related issue ([link](http://stackoverflow.com/q/2947820/335858)). [This discussion](http://social.msdn.microsoft.com/Forums/en-US/8c2b0b1c-01bb-4de2-af46-0b4ea866cf8f/the-parameter-xxx-was-not-bound-in-the-specified-linq-to-entities-query-expression) may also be relevant. – Sergey Kalinichenko Sep 03 '13 at 18:23
  • Thats right, its PB issue, my resolution is to use Expand(): `return base.WhereFilter.And(x => x.Products.Count > 0).Expand();` Or create an extension method called AndExpand: `public static Expression> AndExpand(this Expression> expr1, Expression> expr2) { return expr1.And(expr2).Expand(); }` – Umair Sep 04 '13 at 09:47
5

You could simply check whether the inherited property returns null:

public override Expression<Func<CustomerCustomerType, bool>> WhereFilter
{
    get {
        var baseResult = base.WhereFilter;
        if (baseResult == null) {
            return x => x.CustomerID == 1;
        } else {
            return base.WhereFilter.And(x => x.CustomerID == 1);
        }
    }
}

IMO this will be more readable than seemingly pointless dummy values that will make you (or anyone else working with the code) wonder at a later time what that was there fore. (And it will probably even result in a tiny bit less of overhead when running.)

If you insist on using less lines, you can shorten down the if-else expression by using the ?: operator.


EDIT: Thinking about this a little further, you could see it as a drawback that everyone overriding that property will have to write so much code, which may introduce errors. But then, it is a questionable design choice to rely on overriding methods not containing any such errors when calling the inherited code, as with the model you proposed, overriders might just as well return only their new predicate without calling And.

A cleaner design, IMO, would make the virtual property protected, and have it return only the new predicate (or null). The publicly accessible (and non-virtual) property would then be responsible for retrieving any predicates of the current and any superclasses, and combining them with And if there is more than one.

O. R. Mapper
  • 20,083
  • 9
  • 69
  • 114
  • Yes this is true that the user has to write more lines of code, so as I am working in a small application, i would go with the answer from @dasblinkenlight – Umair Sep 03 '13 at 18:01
2

You can do following:

    public virtual Expression<Func<CustomerCustomerType, bool>> WhereFilter    
    {
        get { return customerCustomerType => true; }
    }

which is an expression that always returns true.

Piotr Stapp
  • 19,392
  • 11
  • 68
  • 116
0

if you are in debug, you can't use lambda expressions (EF), you can use this to cheat a linq where, if you use a standard linq, use this sentence with .Compile() at end:

Expression>.Lambda(Expression.Constant(true),Expression.Parameter(typeof(T)))

ModMa
  • 509
  • 4
  • 5