How to do a "where in values" in LINQ-to-Entities 3.5
Asked Answered
M

7

20

Does anybody know how to apply a "where in values" type condition using LINQ-to-Entities? I've tried the following but it doesn't work:

var values = new[] { "String1", "String2" };  // some string values

var foo = model.entitySet.Where(e => values.Contains(e.Name));

I believe this works in LINQ-to-SQL though? Any thoughts?

Mccloskey answered 17/9, 2008 at 22:50 Comment(1)
Related: #6995230Aviv
M
1

It is somewhat of a shame that Contains is not supported in Linq to Entities.

IN and JOIN are not the same operator (Filtering by IN never changes the cardinality of the query).

Maund answered 18/9, 2008 at 3:34 Comment(0)
R
19

Update: found out how to do this. And EF will generate the appropriate SQL on the database. I'm not sure if this is for EF4 only but I got the tip from Entity Framework 4.0 Recipes


var listOfIds=GetAListOfIds();
var context=CreateEntityFrameworkObjectContext();
var results = from item in context.Items
              where listOfIds.Contains(item.Category.Id)
              select item;
//results contains the items with matching category Ids

This query generates the correct in clause on the server side. I haven't tested it with EF 3.5 but it does work with EF4.

NB: The values passed into the in clause are NOT parameters so make sure you validate your inputs.

Revolutionize answered 17/9, 2008 at 23:23 Comment(3)
Ok, I finally got around to testing this. Unfortunately it doesn't work for what I'm doing but I did find the answer here: forums.microsoft.com/MSDN/… Thanks for the help though, ur still a champ!Mccloskey
Well that's a serious effin' bug! Sorry to hear that it doesn't work. Be careful with that solution because it's prone to SQL injection (using string composition in the middle of your expression) If it were pure Linq to objects, this would work.Revolutionize
Yea I know, it is annoying. I will have to sanitize the inputs before using them inside the ESQL.Mccloskey
M
1

It is somewhat of a shame that Contains is not supported in Linq to Entities.

IN and JOIN are not the same operator (Filtering by IN never changes the cardinality of the query).

Maund answered 18/9, 2008 at 3:34 Comment(0)
V
1

Contains is not supported in EF at this time.

Vivia answered 18/9, 2008 at 20:5 Comment(0)
E
1

FYI:

If you are using ESql you are able to use in operation. I don't have VS 2008 With me but code should be something like following:

var ids = "12, 34, 35";
using (context = new Entites())
{
    var selectedProducts = context.CreateQuery<Products>(
        String.Format("select value p from [Entities].Products as p 
                       where p.productId in {{{0}}}", ids)).ToList();
    ...
}
Ethos answered 30/3, 2010 at 7:0 Comment(0)
H
1

For the cases when you want to use expressions when querying your data, you can use the following extension method (adapted after http://social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/095745fe-dcf0-4142-b684-b7e4a1ab59f0/):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Data.Objects;

namespace Sample {
    public static class Extensions {
        public static IQueryable<T> ExtWhereIn<T, TValue>(this ObjectQuery<T> query,
                    Expression<Func<T, TValue>> valueSelector,
                    IEnumerable<TValue> values) {
            return query.Where(BuildContainsExpression<T, TValue>(valueSelector, values));
        }
        public static IQueryable<T> ExtWhereIn<T, TValue>(this IQueryable<T> query,
            Expression<Func<T, TValue>> valueSelector,
            IEnumerable<TValue> values) {
            return query.Where(BuildContainsExpression<T, TValue>(valueSelector, values));
        }
        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();
            // p => valueSelector(p) == values[0] || valueSelector(p) == ...
            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>((accumulate, equal) => Expression.Or(accumulate, equal));
            return Expression.Lambda<Func<TElement, bool>>(body, p);
        }
    }
    class Program {
        static void Main(string[] args) {
            List<int> fullList = new List<int>();
            for (int i = 0; i < 20; i++) {
                fullList.Add(i);
            }

            List<int> filter = new List<int>();
            filter.Add(2);
            filter.Add(5);
            filter.Add(10);

            List<int> results = fullList.AsQueryable().ExtWhereIn<int, int>(item => item, filter).ToList();
            foreach (int result in results) {
                Console.WriteLine(result);
            }
        }
    }       
}

Using the extensions is really easy (as you can see in the sample). To use it on a database object, assuming you are filtering a table called "Product" by more than one id, you could do something like that:

class Product {
    public int Id { get; set; }
    /// ... other properties
}


List<Product> GetProducts(List<int> productIds) {    
    using (MyEntities context = new MyEntities()) {
        return context.Products.ExtWhereIn<Product, int>(product => product.Id, productIds).ToList();
    }
}
Hypersensitize answered 21/1, 2011 at 14:0 Comment(4)
Did you try apply your solution for a big list?Eardrum
Not really, I've used this on several projects and never had any problem. I guess I doesn't matter anymore, since EF2 already has this feature with the .Contains() extensionHypersensitize
Completely stupid to vote this answer down. The need for such a complicated and possibly slow workaround is not the fault of the one who provided this answer but of EF 1. (Fixed: +1)Complot
This actually generates a WHERE ((1 = [Extent1].[Id]) OR (2 = [Extent1].[Id]) OR (3 = [Extent1].[Id])) etc, not the expected WHERE Id IN (1, 2, 3), which works both ways I guess.Lanellelanette
C
0

Yes it does translate to SQL, it generates a standard IN statement like this:

SELECT [t0].[col1]
FROM [table] [t0]
WHERE [col1] IN ( 'Value 1', 'Value 2')
Curnin answered 17/9, 2008 at 22:52 Comment(1)
When using LINQ-to-Entities ala the ADO.NET Entity Framework, I get an exception saying the "Contains" couldn't be translated. I know what it should translate to but it's not working.Mccloskey
A
0

Using the where method doesn't alway work

var results = from p in db.Products

             where p.Name == nameTextBox.Text

             select p;
Abubekr answered 17/9, 2008 at 22:54 Comment(1)
Thanks Gabe. I'm aware of the alternate LINQ syntax and it works exactly the same way. My question here is how to do the "where in values" types condition.Mccloskey

© 2022 - 2024 — McMap. All rights reserved.