3

I have an Entity Framework class set up to read a table from a SQL database, but I can't quite figure out how to pass a LINQ expression to filter only certain objects. I know there is a way to build an expression tree and do this dynamically from within the class, but I can't seem to figure the best way to do this.

Any tips are appreciated.

class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
}

class MyObjectCollection<T> where T : class
{
    private List<T> myInternalCollection = new List<T>();

    MyObjectCollection()
    {
        using (var db = new MyContext()) 
        {
            foreach (T row in db.Set<T>())
            {
                // Enumerate the data, do whatever with it...
                myInternalCollection.Add(row);
            }
        }
    }

    MyObjectCollection(var MyLinqExpression)
    {
        using (var db = new MyContext()) 
        {
            foreach (T row in db.Set<T>().Where.MyLinqExpression()
            {
                // Enumerate the data, do whatever with it...
                myInternalCollection.Add(row);
            }
        }
    }
}

// Works fine:
MyObjectCollection<Customer> allCustomers = new MyObjectCollection<Customer>();

// Would like something like this:
MyObjectCollection<Customer> customersP = new MyObjectCollection<Customer>(c => c.StartsWith("P"));
Brian Wirt
  • 142
  • 3
  • 9

1 Answers1

4

The Linq Where method takes a parameter of Func<T, bool> where T would be the dbSet object type you want to apply your Where method on.

So to make your code work, you can do this:

public MyObjectCollection(Func<T, bool> MyLinqExpression)
{
    using (var db = new MyContext())
    {
        foreach (T row in db.Set<T>().Where(MyLinqExpression))
        {
            // Enumerate the data, do whatever with it...
            myInternalCollection.Add(row);
        }
    }
}

UPDATE: Also, to achieve the functionality you are looking for with a generic collection, instead of encapsulating a private List object, you could inherit from List like I show below. So, if you wanted MyObjectCollection to function like a List, you can do something like I show below.

So with your code from above, you can change to this:

public class MyObjectCollection<T> : List<T> where T : class
{
    public MyObjectCollection()
    {
        using (var db = new MyContext())
        {
            foreach (T row in db.Set<T>())
            {
                // Enumerate the data, do whatever with it...
                this.Add(row);
            }
        }
    }

    public MyObjectCollection(Func<T, bool> MyLinqExpression)
    {
        using (var db = new MyContext())
        {
            foreach (T row in db.Set<T>().Where(MyLinqExpression))
            {
                // Enumerate the data, do whatever with it...
                this.Add(row);
            }
        }
    }
}
Russell Jonakin
  • 1,716
  • 17
  • 18
  • In this instance, where the return type is `bool`, I'd advise using `Predicate` over `Func`. – Abion47 Jan 27 '17 at 01:06
  • 1
    @Abion47 I have always used `Func` for where methods. I think Predicate would work, but `Func` is how the Where method is implemented, and since .NET 3.5 for these types of methods Func is recommended over Predicate... but it is a thin line though. Here is a Nice Stack post on the topic - Jon Skeet and Marc Gravell both weigh in on the topic here too http://stackoverflow.com/questions/665494/why-funct-bool-instead-of-predicatet – Russell Jonakin Jan 27 '17 at 02:16
  • 2
    I'm not sure if inheritance is better than aggregation in this example. By inheriting you allow others to change myInternalCollection, which is apparently not needed for the class to function as described, otherwise myInternalCollection would not have been defined private. Besides using this inheritance limits possibilities to change myInternalCollection, for instance into a Dictionary, or into a collection of other items. Advise: don't make your data publicly accessible unless the usage of the class requires – Harald Coppoolse Jan 27 '17 at 07:48
  • 2
    @HaraldCoppoolse yea, great point, you are right. I made an assumption based on the Collection part of the class name of `MyObjectCollection`. It would probably be better to implement IEnumerable to iterate if needed, or ICollection if you were wanting to expose and control some of the functionality that acts over your private List if needed... But if the OP was wanting to completely hide away any exposure to the internal List object, then I was completely wrong in my assumption. Which happens a lot when I assume : ) – Russell Jonakin Jan 27 '17 at 14:11
  • Thanks guys. Super helpful. I went with Func, works great! :) – Brian Wirt Feb 03 '17 at 22:24