我有2个对象(尝试使其工作有点像SO)与many to many
关系,我想基于另一个过滤它们的一个集合。这是我的目标:
public class Code
{
public int CodeId { get; set; }
public string CodeName { get; set; }
public string CodeData { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
public class Tag
{
public int TagId { get; set; }
public string Name { get; set; }
public string Comments { get; set; }
public virtual ICollection<Code> Codes { get; set; }
}
因此,如果我想要过滤Tags
的集合,我想要返回Codes
的集合,其tags
至少包含一个所选标签,但是Tag
中不存在选定Tags
中的Code
我尝试使用Linq
,但最终得到了这个非linq解决方案:
public IEnumerable<Code> GetCodes()
{
//A collection to filter upon
var SelectedTags = new List<Tag>();
//the collction to return
var FoundCodes = new List<Code>();
foreach (Code code in GetAllCodes())
{
foreach (var tags in code.Tags)
{
if (SelectedTags.Contains(tags))
{
if (!FoundCodes.Contains(code))
{
FoundCodes.Add(code);
}
continue;
}
}
foreach (var selectedTags in SelectedTags)
{
if (!code.Tags.Contains(selectedTags))
{
FoundCodes.Remove(code);
}
}
}
return FoundCodes;
}
所以我的问题是我如何使用Linq
?
答案 0 :(得分:2)
var foundCodes = GetAllCodes()
.Where(code => code.Tags.All(t => SelectedTags.Contains(t)))
.Distinct()
.ToList();
如果GetAllCodes()
返回不同的结果,您可以省略Distinct
来电。
继续@ Nuffin的评论,
你可以试试,
SelectedTags = SelectedTags.OrderBy(t => t).ToList();
var foundCodes = GetAllCodes()
.Where(code =>
code.Tags
.OrderBy(t => t)
.SequenceEqual(SelectTags))
.Distinct()
.ToList();
但是,我怀疑您的查询提供程序无法将SequenceEqual
转换为语句。
在这种情况下,请使用@ Nuffin的答案。
答案 1 :(得分:2)
这个简单的查询应该可以解决问题(找到所有选定标签的代码,而不是其他标签):( 请注意,虽然这段代码完全模仿了OP的实现行为,但这并不是理想的结果。下面是固定版本)
public IEnumerable<Code> GetCodes()
{
var SelectedTags = new List<Tag>(); /* fill this however */
return from code in GetAllCodes() /* get all codes*/
where SelectedTags.All(code.Tags.Contains) /* filter out codes with nonmatching tags */
where code.Tags.All(SelectedTags.Contains) /* filter out codes with missing tags*/
select code; /* return the remaining codes */
}
请注意,根据不同标签的数量,这可能会很慢,而不使用针对搜索进行优化的集合(尽管仍然比您的解决方案快一点)。
编辑:要获得图片上显示的结果(获取所有选定代码的所有代码,无论代码中包含其他代码),只需省略第二个where子句:
public IEnumerable<Code> GetCodes()
{
var SelectedTags = new List<Tag>(); /* fill this however */
return from code in GetAllCodes() /* get all codes*/
where SelectedTags.All(code.Tags.Contains) /* filter out codes with nonmatching tags */
select code; /* return the remaining codes */
}
答案 2 :(得分:0)
也许你可以这样缩短:
public IEnumerable<Code> GetCodes()
{
//A collection to filter upon
var SelectedTags = new List<Tag>();
//the collction to return
var FoundCodes = new List<Code>();
foreach (var code in GetAllCodes())
{
foreach (var tags in code.Tags.Where(tags => SelectedTags.Contains(tags)))
{
if (!FoundCodes.Contains(code))
{
FoundCodes.Add(code);
}
continue;
}
foreach (var selectedTags in SelectedTags.Where(selectedTags => !code.Tags.Contains(selectedTags)))
{
FoundCodes.Remove(code);
}
}
return FoundCodes;
}
也许你可以发帖GetAllCodes()
...问题是因为foreach中的循环我不知道如何将它缩短为linq方法链。