I'm working on a large application which is using Dynamic LINQ Library for filtering .
All of the classes in my data-access-layer are derived from a common ancestor DALAncestor which, among other things, defines method GetData: public abstract List GetData(Filter filter)
An implementation of this method for a Customer would look like this (simplified):
public override List<Entities.Customer> GetData(Filter filter) {
  var customers = from c in db.Customers
                  select new Entites.Customer { 
                    ID = c.ID,
                    FullName = c.Name,
                    Country = c.Country
                  };
   return = filter.Apply(customers).ToList();
}
"Apply" is a method which takes a collection of conditions and applies all of them using Dynamic LINQ Libary.
Method GetData is called like this:
private void DemoCallGetDataMethod() {
  var filter = new Filter();
  filter.AddCondition("Country", "Austria");
  var list = myCustomerDAL.GetData(filter);
  // do something
}
SQL Server gets a select statment:
SELECT [t0].ID, [t0].Name, [t0].Country
  FROM Customer [t0]
 WHERE [t0].Country = @p0
(@p0 is a parameter with its value set to "Austria").
Everything works great, if I want to filter values only on the "top" (master) level. However, since I build my filter on user's input on the filter form, there are cases in which users want to filter by a value in detail level (i.e. columns to be filtered by are known only after a user clicks "Search").
I cannot find a solution for this: "Get all of the customers from Austria, who bought Pepsi".
I've tried several things, none of them seems to be working. The basic idea is:
1. Add support for CONTAINS to DynamicLibrary
2. Change my code to
public override List<Entities.Customer> GetData(Filter filter) {
  var customers = from c in db.Customers
                  select new Entites.Customer { 
                    ID = c.ID,
                    FullName = c.Name,
                    Country = c.Country,
                    Items = c.Order.SelectMany(o => o.Item).Select(i => i.ItemId).ToList()
                  };
  return = filter.Apply(customers).ToList();
}
private void DemoCallGetDataMethod() {
  var filter = new Filter();
  filter.AddCondition("Country","=", "Austria");
  filter.AddCondition("Items","Contains", "11"); // 11 = Id for Pepsi
  var list = myCustomerDAL.GetData(filter);
  // do something
}
The exepction thrown is:
System.InvalidOperationException: No generic method 'Contains' on type 'System.Linq.Enumerable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.
Does anyone have any idea what I'm doing wrong? Or am I just going in wrong direction and I should try a some other approach? Which? :)
EDITED: changed my example
@user182630 I want to be able to filter by values from subselects in general, not only for a specific case. The approach from that article works only if you hard code you filters, which is not a thing I can do. – Marko Juvančič 9 mins ago
Have a read through this article http://csharpindepth.com/articles/chapter5/closures.aspx
I use PredicateBuilder for dynamic queries in my applications.
Predicate Builder
In your case I imagine it will be something like:
 string MyCountry = "Austria";
 string MyProductId = 11
 var Predicate = PredicateBuilder.True<db.Customers>();
 Predicate = Predicate.And(p=>p.Country ==MyCountry && p.Order.SelectMany(o=>o.Item).Where(i=>i.id == 11).Count() >0);
 var list = Customers.Where(Predicate).Select(s=>s).ToList();
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With