views:

36

answers:

1

I am using SL 4, WCF RIA Services against Entity Framework 4.0. I have an Entity, Visit, that has a string Status field. I have a search screen where I need to display results that have StatusA or StatusB. I am struggling to find a way to specify a client-side query that specifies a collection of statuses that should be matched. If I was to write what I want in SQL it would look something like:

select * from Visit where Status in ('StatusA', 'StatusB');

Client side, it appears to be straightforward to chain Where methods for a WhereAnd effect:

        var query = this.PqContext.GetVisitsQuery();

        if (!string.IsNullOrEmpty(this.PracticeName))
        {
            query = query.Where(v => v.PracticeName.ToUpper().Contains(this.PracticeName.ToUpper()));
        }

        if (this.VisitDateAfter.HasValue)
        {
            query = query.Where(v => v.VisitDate > this.VisitDateAfter);
        }

        if (this.VisitDateBefore.HasValue)
        {
            query = query.Where(v => v.VisitDate < this.VisitDateBefore);
        }

However, I can't seem to find a straightforward way to do a WhereOr style operation. I have tried this:

        var statuses = new List<string>();

        if (this.ShowStatusA)
        {
            statuses.Add("StatusA");
        }

        if (this.ShowStatusB)
        {
            statuses.Add("StatusB");
        }

        if (statuses.Any())
        {
            query = query.Where(BuildContainsExpression<Visit, string>(e => e.Status, statuses));
        }

Where BuildContainsExpression looks like:

        private static Expression<Func<TElement, bool>> BuildContainsExpression<TElement, TValue>(Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
    {

        if (null == valueSelector)
        {
            throw new ArgumentNullException("valueSelector");
        }

        if (null == values)
        {
            throw new ArgumentNullException("values");
        }

        ParameterExpression p = valueSelector.Parameters.Single();
        if (!values.Any())
        {
            return e => false;
        }

        var equals =
            values.Select(
                value =>
                (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value, typeof(TValue))));

        var body = equals.Aggregate<Expression>(Expression.Or);

        return Expression.Lambda<Func<TElement, bool>>(body, p);
    }

But this throws a "Bitwise operators are not supported in queries." exception. Any clues? Is there an alternative way to build an expression tree that works here or do I need to pass all the parameters over to the server and use the BuildContainsExpression there?

Your time and your guidance are much appreciated.

+1  A: 

You can create a query method such as the following in your domain service:

GetVisitsByStatus(string[] statusList) {
  // create the LINQ where clause here
}

And then from the client, call context.GetVistsByStatusQuery(string[]).

Not all of LINQ is (or even can) be exposed over the URL, so there are always cases where you need to use simple parameters, and have the middle tier construct the LINQ expressions that eventually define the query that goes to the back-end data store.

Hope that helps.

NikhilK
Thanks - I appreciate the pointer.
DarenMay