确保记录具有所有关系,而不是任何

时间:2016-12-01 21:05:04

标签: c# linq iqueryable

我有一个我正在研究的linqpad脚本并且它可以工作,但问题是它使用.AsEnumerable()将集合调用到内存中。有一天可能会有成千上万的这些,所以我想尽可能地推迟一切。

我正在尝试简单地执行检查,以确保我是否将new long[] { 2, 4 }传递给该功能,然后是两者 ID为2和4的任何体验将被退回。

以前,我只使用.Contains(),但这会返回 2或4的体验

是否有更好的方法来编写此代码,以便它返回IQueryable<Experience>而不是List<Experience>,因此我不必将所有结果加载到内存中以执行字符串连接?

void Main()
{
    var AllExperiences = new List<_Experience>();
    AllExperiences.Add(new _Experience { Id = 1, Name = "Experience 1" });
    AllExperiences.Add(new _Experience { Id = 2, Name = "Experience 2" });

    AllExperienceTags.Add(new _ExperienceTag { ExperienceId = 1, TagId = 2 });
    AllExperienceTags.Add(new _ExperienceTag { ExperienceId = 1, TagId = 4 });
    AllExperienceTags.Add(new _ExperienceTag { ExperienceId = 2, TagId = 2 });

    var experiences = FilterBySelectedTags(AllExperiences, new[] { 2, 4 }.ToList());

    experiences.Dump();
}

public List<_ExperienceTag> AllExperienceTags = new List<UserQuery._ExperienceTag>();

// Define other methods and classes here
public List<_Experience> FilterBySelectedTags(List<_Experience> experiences, List<int> selectedTagIds)
{
    var filteredExperiencesTags = AllExperienceTags.Where(x => selectedTagIds.Contains(x.TagId));

    var obj = filteredExperiencesTags.OrderBy(x => x.TagId).GroupBy(x => x.ExperienceId).AsEnumerable().Select(x => new
    {
        ExperienceId = x.Key,
        ExpTags = string.Join(", ", x.Select(y => y.TagId))
    });

    var filteredTags = obj.Where(x => x.ExpTags == string.Join(", ", selectedTagIds));

    // make sure all the selected tags are found in the experience, not just any
    return experiences.Where(x => filteredTags.Select(y => y.ExperienceId).Contains(x.Id)).ToList();
}

public class _Experience
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class _ExperienceTag
{
    public int ExperienceId { get; set; }
    public int TagId { get; set; }
}

2 个答案:

答案 0 :(得分:3)

Experience实体应具有ExperienceTags的导航属性:

public virtual ICollection<ExperienceTag> ExperienceTags{get;set;}

如果是这种情况,这应该有效:

var query= from e in Experiences
           let experienceTagIds=e.ExperiencesTags.Select(et=>et.TagId)
           where selectedTagIds.All(x=>experienceTagIds.Contains(x))
           select e;

答案 1 :(得分:1)

假设有经验,上面有导航属性标签,那么你可以这样做:

void Main()
{
    var experiences = Experiences.FilterBySelectedTags(new long[] { 2, 4 });

    experiences.Dump();
}
public static class ExperienceExtensions {
  public static IQueryable<Experience> FilterBySelectedTags(this IQueryable<Experience> experiences, IEnumerable<long> selectedTagIds)
  {
    return experiences.Where(e=>selectedTagIds.All(id=>e.Tags.Any(t=>t.TagId==id)));
  }
}