Search code examples
c#linqentity-framework.net-3.5linq-to-entities

'Contains()' workaround using Linq to Entities?


I'm trying to create a query which uses a list of ids in the where clause, using the Silverlight ADO.Net Data Services client api (and therefore Linq To Entities). Does anyone know of a workaround to Contains not being supported?

I want to do something like this:

List<long?> txnIds = new List<long?>();
// Fill list 

var q = from t in svc.OpenTransaction
        where txnIds.Contains(t.OpenTransactionId)
        select t;

Tried this:

var q = from t in svc.OpenTransaction
where txnIds.Any<long>(tt => tt == t.OpenTransactionId)
select t;

But got "The method 'Any' is not supported".


Solution

  • Update: EF ≥ 4 supports Contains directly (Checkout Any), so you don't need any workaround.

    public static IQueryable<TEntity> WhereIn<TEntity, TValue>
      (
        this ObjectQuery<TEntity> query,
        Expression<Func<TEntity, TValue>> selector,
        IEnumerable<TValue> collection
      )
    {
      if (selector == null) throw new ArgumentNullException("selector");
      if (collection == null) throw new ArgumentNullException("collection");
      if (!collection.Any()) 
        return query.Where(t => false);
    
      ParameterExpression p = selector.Parameters.Single();
    
      IEnumerable<Expression> equals = collection.Select(value =>
         (Expression)Expression.Equal(selector.Body,
              Expression.Constant(value, typeof(TValue))));
    
      Expression body = equals.Aggregate((accumulate, equal) =>
          Expression.Or(accumulate, equal));
    
      return query.Where(Expression.Lambda<Func<TEntity, bool>>(body, p));
    }
    
    //Optional - to allow static collection:
    public static IQueryable<TEntity> WhereIn<TEntity, TValue>
      (
        this ObjectQuery<TEntity> query,
        Expression<Func<TEntity, TValue>> selector,
        params TValue[] collection
      )
    {
      return WhereIn(query, selector, (IEnumerable<TValue>)collection);
    }
    

    USAGE:

    public static void Main()
    {
      using (MyObjectContext context = new MyObjectContext())
      {
        //Using method 1 - collection provided as collection
        var contacts1 =
          context.Contacts.WhereIn(c => c.Name, GetContactNames());
    
        //Using method 2 - collection provided statically
        var contacts2 = context.Contacts.WhereIn(c => c.Name,
          "Contact1",
          "Contact2",
          "Contact3",
          "Contact4"
          );
      }
    }