【问题标题】:Linq optimized intersect queryLinq 优化的相交查询
【发布时间】:2012-08-18 04:58:35
【问题描述】:

我有这样的结构:

public class Tag
{
        public int TagId { get; set; }
        public virtual ICollection<Vacancy> Vacancies { get; set; }
        // ...
}

public class Vacancy
{
        public int VacancyId { get; set; }
        public virtual ICollection<Tag> Tags { get; set; }
        // ...
}

这些实体通过 EF / Code First 方法映射到 MS SQL。

之后,我以某种方式从上下文(基于用户查询)中获取标签列表:

List<Tag> userSelectedTags = ...;

我想选择包含所有(!)这些标签的所有空缺,例如:

List<Vacancy> vacancies = context.Where(v => v.Tags.Intersect(userSelectedTags)).ToList();

但是!问题是我可能有大量数据。 AFAIK Intersect 并不是最好的方法,因为它会为每个空缺选择所有标签,然后对它们执行 Intersect。我不想过多地加载 SQL Server,我绝对可以为此编写纯 sql 查询。但我想知道 LINQ 是否可以为我做这件事?有没有更温和的方法?

【问题讨论】:

标签: c# linq entity-framework


【解决方案1】:

Arkiliknam 的解决方案非常有效,可能是最有效的解决方案,但存在一些问题。我开始在评论中指出它们,以改进答案,但这效果不佳。所以这里是 Arkiliknam v. 2.0:

var result = context.Vacancies; // IQueryable!
var tags = userSelectedTags.Select(t => t.TagId);

foreach(int i in tags)
{
    int j = i; // prevent modified closure.
    result = result.Where(v => v.Tags.Select(t => t.TagId).Contains(j));
}
result.Select(r => ....

它被转换为带有WHERE EXISTS 谓词链的查询(与选定的标签一样多)。

如果效果不佳,您可以尝试另一种方法:

var r = context.Vacancies
.Where(v => tags.All(i => v.Tags.Select(t => t.TagId).Contains(i)))
.Select (v => ....);

这表示对于所有选定的 TagIds,每个 Id 都应该在 VacancyTagIds 集合中。

【讨论】:

    【解决方案2】:

    不确定这是否会更有效,但我想如果您将其保留为 IQueryable 应该可以吗?

    IEnumerable<Vacancy> result = vacancies;
    
    foreach(var t in tags){
        result = result.Where(v => v.TagIds.Contains(t));
    }
    

    【讨论】:

      猜你喜欢
      • 2012-03-07
      • 2019-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多