选择包含所有标签的产品

时间:2014-04-02 13:10:19

标签: c# linq entity-framework

我正在使用C#和Entity Framework。我有一个包含我的产品的Products表(Id, Name),一个包含所有可用标记的Tags表(Id, Name)和一个用于为其分配标记的ProductTags表(Id, ProductId, TagId)产品。 用户可以指定他想要查看具有多个标签(Int[] SelectedTagIds)的产品。 问题是:如何获得所有产品,每个产品都有用户指定的所有标签。

现在我正在使用此查询

`var reault = Context.Products
                     .Where(x => SelectedTagIds.All(y => 
                           (x.ProductTags.Select(z => z.TagId))
                     .Contains(y)));`

我想知道这是正确的方式还是更好/更快的方式?

1 个答案:

答案 0 :(得分:2)

你可以使用intersect,然后检查两者的长度,确保相交的数量与搜索标签的数量相同,这意味着所有搜索标签都存在于ProductTags集合中。

        var result =
            products.Where(
                x => x.ProductTags.Intersect(searchTags).Count() == searchTags.Length);

但您需要运行性能分析,这对您更有效。但正如奥伦评论的那样,你真的遇到了性能问题吗?由于这两个集合很可能都很小,所以不会造成瓶颈。

编辑:刚检查了交叉的性能,它比使用.All与.Contains

我的机器上的Perf,创建1000个结果查询并使用ToList()枚举它们,在一组1000个产品上,带有2个搜索标签,为我提供了以下性能:

searchTags.All(search => x.ProductTags.Contains(search)) = 202ms

!searchTags.Except(x.ProductTags).Any() = 339ms

x.ProductTags.Intersect(searchTags).Count() == searchTags.Length = 389ms

如果您确实需要提高性能,可以将HashSet用于ProductTags和SelectedTagIds

编辑2:使用哈希集比较

使用hashsets运行比较并获得以下输出创建1000个查询对象并使用ToList()执行列表给出了以下结果:

使用List<Tag>

Creating Events took 6ms
Number of Tags = 3000
Number of Products = 1003
Average Number of Tags per Products = 100
Number of Search Tags = 10

.All.Contains = 5379ms - Found 51
.Intersect = 5823ms - Found 51
.Except = 6720ms - Found 51

使用HashSet<Tag>

Creating Events took 26ms
Number of Tags = 3000
Number of Products = 1003
Average Number of Tags per Products = 100
Number of Search Tags = 10

.All.Contains = 259ms - Found 51
.Intersect = 6417ms - Found 51
.Except = 7347ms - Found 51

正如您所看到的,即使您考虑额外的20ms来创建HashSet,使用HashSet也要快得多。虽然哈希是ID字段的简单哈希。如果你要使用更复杂的哈希结果会有所不同。