1

I'm trying to implement a generic method with predicate. I wrote some code:

public ICollection<T> GetProductsByMatching<T>(Expression<Func<T, bool>> predicate)
{
    return context.Products.Where(predicate).Include("ShopPlace, Images").ProjectTo<T>().ToList();
}

And usage of this method:

var a = service.GetProductsByMatching<ProductInfo>(x => x.Name.StartsWith("value") 
        || x.Price < 150);

Finally I have Invalid Operation Exception: No generic method 'Where' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments.

Whats wrong with my code? Thanks for advance!

SᴇM
  • 7,024
  • 3
  • 24
  • 41
user3818229
  • 1,537
  • 2
  • 21
  • 46
  • Because `T` != `Product`. What is this code supposed to do? Do you mean to call `context.Set` instead? – CodeCaster Mar 31 '16 at 11:20
  • @CodeCaster get products from database by predicate and map it to ProductInfo (ViewModel class) – user3818229 Mar 31 '16 at 11:22
  • Yes, _that_ part is obvious from the code, but I'm trying to find out your reason for typing `Expression>` in the first place. In my answer I now made some assumptions based on the method name. – CodeCaster Mar 31 '16 at 11:26

1 Answers1

3

The predicate in context.Products.Where(predicate) can obviously only be an Expression<Func<Product, bool>>, not a Expression<Func<T, bool>>, because there's no guarantee that T is a Product.

You're trying to filter on the a predicate on the destination type, while the filtering must occur on the source type:

public ICollection<T> GetProductsByMatching<T>(Expression<Func<Product, bool>> predicate)
{
    return context.Products.Where(predicate)
                           .Include("ShopPlace, Images")
                           .ProjectTo<T>()
                           .ToList();

}
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • I suspected so. But I don't want to have links to `Product` class in method usage scope. It is possible to write function to filter products by `ProductInfo` field? – user3818229 Mar 31 '16 at 11:27
  • That's an entirely different question altogether. You can't do it with ProductInfo (because that class has no relation to Product whatsoever, and could contain properties that your Product doesn't contain, so your expression can't be translated to non-existent columns in your database). You could add an interface layer, where consumers query on the interface, and you apply that interface to your entity models. – CodeCaster Mar 31 '16 at 11:29
  • Is there any way to transform/modify/map source predicate based on `ProductInfo` class to `Product` class if I'm sure about identical properties. I mean to save body of expression but cast predicate to another type. – user3818229 Mar 31 '16 at 11:36
  • That too, is an entirely different question. See for example [How do I translate an expression tree of one type to a different expression type?](http://stackoverflow.com/questions/6698553/how-do-i-translate-an-expression-tree-of-one-type-to-a-different-expression-type). – CodeCaster Mar 31 '16 at 11:39