我有这样的结构:
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能否为我做到这一点?有没有更温和的方式呢?
答案 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));
}