tags:

views:

64

answers:

3

I would like to query data given an array to filter by via WCF Data Services using the Silverlight Client API. Basically, I want to query Employees given a list (array) of States.

I'm thinking something like this:

public IQueryable<Employee> Load(string[] states)
{
     foreach (var x in states)
     {
           // LINQ query here with 1 to N .Where statements
           return from e in Context.Employees
           .Where(...)
     }
} 

So let's say my array has 2 items in it, i.e. I want to query by 2 states, I would do something like this manually:

return from e in Context.Employees
    .Where(e => e.State== states[0] || e.State == states[1])));

Any advice will be greatly appreciated!

+1  A: 

Context.Employees.ToList().Where(x => states.Contains(x.State))

grrrrrrrrrrrrr
This will not work with EntityFramework or LINQ to SQL. I assume one if this is used because the parameter is `IQeryable` and not `IEnumerable`.
Daniel Brückner
it should do if you call tolist() before the where.
grrrrrrrrrrrrr
You may want to consider performance if this is a large table though as all employees would be read in, then the filter applied
grrrrrrrrrrrrr
He will have to test it but I am quite sure that neither EF nor L2S is capable of translating a complex object like a list into a matching SQL statement - at least prior to .NET 4.0.
Daniel Brückner
your right(I think), but tolist converts it into a normal list object, so even if ef or l2s don't support it you should be dealing with L2o at that point. The query has already been executed on the db when running the filter. I would test it without tolist first as that would be more efficient if it worked.
grrrrrrrrrrrrr
As per my latest edits on the original post, looks like "Contains" is not supported: {Error translating Linq expression to URI: The method 'Contains' is not supported.}
Ahhh, sorry, now I see it - I always missed the `ToList()` after `context.Employees`. I assumed you wanted to turn the `states` array into a list as in DOK's answer. Of course, this will work - it will fetch all employees from the database into a list in memory and then perform the `Contains()` using LINQ to Object. The obvious problem with this is that it will fetch all rows from the database only to find a few of them locally. For all but the most simple real world scenarios you really don't want to fetch a whole table with possibly thousands or millions of rows for local processing.
Daniel Brückner
Yep, at first the tolist wasn't there, but then i remembered ef does not support that kind of translation, the tolist was kind of a compromise for this. If it is a small table, I would use this as unless your talking about a lot of data, it should work fine.
grrrrrrrrrrrrr
A: 

Here's a runnable example that does what you want, I think? Given a list of states, it will give you the employees that are in those states.

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> states = new List<string>();
            states.Add("SC");
            states.Add("TX");
            states.Add("NC");

            List<Employee> emps = new List<Employee>();
            emps.Add(new Employee() { State = "GA", Name = "Bill" });
            emps.Add(new Employee() { State = "TX", Name = "John" });
            emps.Add(new Employee() { State = "SC", Name = "Mary" });

            //Here's where the work is done.  The rest is fluff...
            var empsinstates = from e in emps where states.Contains(e.State) select e;

            foreach (var e in empsinstates)
            {
                Console.WriteLine(e.Name + " " + e.State);
            }
            Console.Read();
        }
    }
    class Employee
    {
        public string State;
        public string Name;
    }
}
Tim Coker
This works with LINQ to Object but (quite surely) not with Entity Framework or LINQ to SQL.
Daniel Brückner
This is what I am getting: {Error translating Linq expression to URI: The method 'Contains' is not supported.}
+1  A: 

You can dynamically build the expression tree for the condition.

var parameter = Expression.Parameter(typeof(Employee), "employee");

Expression condition = Expression.Constant(false);

foreach (var state in states)
{
    condition = Expression.OrElse(
        condition,
        Expression.Equal(
            Expression.Property(parameter, "State"),
            Expression.Constant(state)));
}

var expression = Expression.Lambda<Func<Employee, Boolean>>(condition, parameter);

And then just perform the call.

var result = Context.Employees.Where(expression);

I am not 100% sure if this will work out of the box for you but I hope the general idea helps.

Daniel Brückner
Probably not `Or` but `OrElse`. And `Parameter(typeof(Employee)...`
Yury Tarabanko
Thanks, you are right - I wrote the code using a list of `String` for testing and forgot to change it to `Employee`. The difference between `Or` and `OrElse` should not matter but one would of course usually use a conditional or instead of the normal or.
Daniel Brückner