繁体   English   中英

如何在“WHERE”条件下使用List编写LINQ to Entities查询

[英]How to write a LINQ to Entities query with List in a “WHERE” condition

我想知道以列表作为条件编写最有效的LINQ( 编辑 :实体)查询。 这就是事情。

可以说我们有以下数据结构:

 public class Recipe
 {
   public int Id;
   public string Name;
   public List<Ingredient> IngredientList;
 }

 public class Ingredient
 {
   public int Id;
   public string Name;
 }

现在,我想做一个查询,搜索所有具有所有给定成分的食谱。

 public List<Recipe> GetRecipesWhichHaveGivenIngredients(List<Ingredients> ingredients)
 {
   List<Recipe> recipes;

   using (DataContext context = new DataContext())
   {
    //efficient LINQ query goes here
    recipes = context.Recipes.Where(recipe => /*medaCode recipe.IngredientList.Contains(ingredients) */).ToList();
   }
   return recipes;
 }

基本上这是如何确定给定集合是否是另一集合的子集的问题。

我尝试过以下查询(主要思想是使用Intersect操作):

List<Recipe> recipes = dataContext.Recipes.Include("Ingrediens").Where(rec => rec.IngredientList.Select(ingr => ingr.Id).Intersect(ingredients.Select(sy =>  sy.Id)).Count() == ingredients.Count).ToList();

但是我收到以下错误:

无法创建“闭包类型”类型的常量值。 在此上下文中仅支持原始类型(例如Int32,String和Guid')。

好吧,如果IngredientList真的是List<T> ,你将能够做到:

recipes = context.Recipes.Where(recipe => recipe.IngredientList.Exists(i => i.Id == ingredient.Id)).ToList();

但这意味着需要填充所有列表。 由于这看起来像LINQ to SQL查询,我猜测IngredientList只是一个连接表......? 在这种情况下,您将没有完整列表,但您仍然可以执行类似的操作:

recipes = context.Recipes.Where(recipe => recipe.IngredientList.Count(i => i.Id == ingredient.Id) > 0).ToList();

...它应该仍然只查询一次sql server。

编辑

正如评论中刚才指出的那样,这并没有完全回答这个问题。 至于包含所有搜索,我认为没有循环输入就可以完成。 好的一点是,这可以在不枚举IEnumerable recipes情况下完成,因此下面的代码仍然只需用一个查询就可以访问sql server一次:

var recipes = context.Recipes.AsEnumerable<Recipe>();

ingredients.ForEach(i =>
    var recipes = recipes.Where(r =>
        r.IngredientList.Count(ii => ii.Id == i.Id) > 0
    );
);

return recipes.ToList();

在命中ToList()之前,不会执行查询。

不要使用List<Ingredient>作为您想要找到的成分; 使用HashSet<Ingredient>IsProperSubsetOf方法,该方法接受一个集合作为其参数:

.Where(x => ingredients.IsProperSubsetOf(x.IngredientList))

除了作为O(n + m)操作之外,还有一个额外的好处,就是可以在看到它时告诉你它正在做什么。

编辑

如果上述情况不明确:

public List<Recipe> GetRecipesWhichHaveGivenIngredients(HashSet<Ingredient> ingredients)
{
   using (DataContext context = new DataContext())
   {
       return context.Recipes
           .Where(x => ingredients.IsProperSubsetOf(x.IngredientList)  
           .ToList();
   }
 }

不知道这是否适用于Linq2SQL,但在Linq2Object中,这有效:

public static class Util
{
    public static List<Recipe> GetRecipesWhichHaveGivenIngredients(this List<Recipe> recipies, List<Ingredient> ingredients)
    {
        int icount=ingredients.Count;

        var res = recipies.Where(r => r.IngredientList.Where(i => ingredients.Contains(i)).Count() == icount).ToList();
        return res;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM