我正在使用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)));`
我想知道这是正确的方式还是更好/更快的方式?
答案 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字段的简单哈希。如果你要使用更复杂的哈希结果会有所不同。