2017-02-25 120 views
0

考虑下面的类都值:检查集合包含了另一个集合与延迟执行

public class Recipe 
{ 
    public string Id { get; set; } 
    public ICollection<RecipeFacet> RecipeFacets { get; set; } 
} 

public class RecipeFacet 
{ 
    public string Id { get; set; } 
    public Facet Facet { get; set; } 
    public string RecipeId { get; set; } 
} 

public class Facet 
{ 
    public string Name { get; set; } 
} 

我需要改进现有的查询。我正在考虑使用Linq的延期执行。我如何编写一个仅返回Recipes的Linq查询,其中包含我在Tuples列表中指定的ALL Facets

这是通过Recipes及其Facets循环的原始代码。它的工作原理,但如果我的初始results查询有很多Recipes它很慢。

IQueryable<Recipe> result; //assume we have data here 

string query = "Cuisine:American+Recipe-Type:dinners"; 
IEnumerable<Tuple<string, string>> taxFacets = query 
      .Split(' ') 
      .Select(tf => tf.Split(':')) 
      .Select(tf => new Tuple<string, string>(tf[0], tf[1])) 
      .Distinct(); 

var recipeFacetCollection = result.Select(r => r.RecipeFacets).ToList(); 
var matchedRecipesIds = new List<string>(); 

var recIds = result.Select(r => r.Id).ToList(); 

// initially, include all recipes 
matchedRecipesIds.AddRange(recIds); 

// loop through each recipe's facet collection 
foreach (var col in recipeFacetCollection) 
{ 
    // loop through the tax facets from the query 
    foreach (var tf in taxFacets) 
    { 
     var exists = col.Any(f => f.Facet.Name.Equals(tf.Item2, StringComparison.OrdinalIgnoreCase)); 
     // remove any recipe that is missing a facet 
     if (!exists) 
     { 
      matchedRecipesIds.Remove(col.First().RecipeId); 
     } 
    } 
} 

result = result.Where(r => matchedRecipesIds.Contains(r.Id)); 

我怎样才能有一个很好的Linq查询与延期执行?

更新::

把我的元组到列表允许我做这件事。但是这个查询不会返回我的任何记录。

这是我的准则:

Recipes,即有RecipeFacts的集合,包含Facets有名称= “美国” AND NAME = “晚餐”。

var listFacets = new List<string>() 
{ 
    "American", 
    "dinners" 
}; 

result = result 
     .Where(r => r.RecipeFacets 
     .All(f => !listFacets.Any(t => t.Equals(f.Facet.Name, StringComparison.OrdinalIgnoreCase)))); 

回答

0

我从@ Rimp的帮助下得到了这一点。

WHERE - 过滤
ALL - 要求所有从listFacets
任何值 - 在任何Facets的。

result = result 
    .Where(x => listFacets 
    .All(lf => x.RecipeFacets 
    .Any(f => f.Facet.Slug.Equals(lf, StringComparison.OrdinalIgnoreCase)))); 
0

我不是很确定导致您的代码块是很长,但这里是我能想出

result = result.Where(r => r.RecipeFacets.All(f => taxFacets.Any(t => t.Item1.Equals(f.Facet.Name)))); 

让我知道这是否有助于或不

+0

感谢您的建议。但是我得到这个错误:“无法创建一个'System.Tuple'类型的常量值。在这种情况下,只支持原始类型或枚举类型。 – duyn9uyen

+0

您可以发布您的代码吗?哪行代码会出错? –

+0

我正在使用你的建议。做一个result.toList()抛出该错误。 – duyn9uyen

0

删除感叹号来自listFacets集合中的检查子句。

result = result.Where(r => r.RecipeFacets.All(f => listFacets.Any(t => t.Equals(f.Facet.Name, StringComparison 
1

您的查询逻辑选择listFacets中不存在其构面的所有配方。 @洪晃的逻辑更接近,而选择具有所有他们的面在listFacets

我认为你要选择包含所有listFacets所有配方的食谱。

简化的例子使用字符串列表:

 var listFacets = new[] { "a", "d" }; 
     var recipes = new[] { new[] { "a" }, 
           new[] { "a", "d" }, 
           new[] { "a", "d", "e" }, 
           new[] { "x" } 
     }; 

     // correct query, returns 2 results ad and ade 
     var result = recipes.Where(r => listFacets.All(f => r.Any(rf => rf == f))); 
     // original incorrect query, returns x 
     var result2 = recipes.Where(r => r.All(f => !listFacets.Any(rf => rf == f))); 
+0

由于您简化了对象,所以查询不一样。但谢谢你的建议。我认为@ hung非常接近。 – duyn9uyen

相关问题