How to do a “where in values” in LINQ-to-Entities 3.5

前端 未结 7 1279
时光说笑
时光说笑 2020-12-15 18:42

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         


        
相关标签:
7条回答
  • 2020-12-15 19:19

    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();
        }
    }
    
    0 讨论(0)
  • 2020-12-15 19:24

    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')
    
    0 讨论(0)
  • 2020-12-15 19:26

    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();
        ...
    }
    
    0 讨论(0)
  • 2020-12-15 19:28

    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).

    0 讨论(0)
  • 2020-12-15 19:31

    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.

    0 讨论(0)
  • 2020-12-15 19:35

    Using the where method doesn't alway work

    var results = from p in db.Products
    
                 where p.Name == nameTextBox.Text
    
                 select p;
    
    0 讨论(0)
提交回复
热议问题