Linq优化了交叉查询

时间:2012-08-16 20:20:22

标签: c# linq entity-framework

我有这样的结构:

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不是最好的方法,因为它会为每个空位选择所有标签,然后在它们上执行相交。我不想加载太多SQL Server,我绝对可以为此编写纯SQL查询。但我想知道LINQ能否为我做到这一点?有没有更温和的方式呢?

2 个答案:

答案 0 :(得分:5)

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 => ....);

表示对于所有选定的TagId,每个Id应位于Vacancy的{​​{1}} s集合中。

答案 1 :(得分:1)

不确定这是否会更有效率,但我想如果你把它留作IQueryable它应该没问题?

IEnumerable<Vacancy> result = vacancies;

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