如何在LINQ中查询?

时间:2014-03-08 01:13:37

标签: c# linq hierarchy

我正在尝试在LINQ中编写查询,到目前为止,我无法使其工作。如果我在历史上设法提出最明显的LINQ问题,那么我道歉但我确实需要一些帮助...

以下是我要做的事情的要点:

我有一个关键字类:

class Keyword
{
    public string Name {get; set;}
}

我还有一个文件类:

class File
{
    public IList<Keyword> Keywords { get; set;}
}

现在,假设我有一种按关键字搜索文件的方法:

IEnumerable<File> FindByKeywords(IEnumerable<Keyword> keywords)
{
    // Let's say that Context.Files is a collection of File objects
    //   each of which contains a collection of associated keywords
    //   that may (or may not) match the keywords we get passed as 
    //   a parameter. This is where I need LINQ magic to happen.
    return Context.Files; // How do I select the files by the list of keywords?
}

我已经看到在传入的关键字列表中使用Contains的示例,但这似乎只适用于匹配属性是标量的实例。在我的例子中,匹配属性是另一个关键字列表。

换句话说,这不起作用:

IEnumerable<File> FindByKeywords(IEnumerable<Keyword> keywords)
{
    return Context.Files.Where(x => keywords.Contains(x);
}

有人有什么想法吗?我真的只需要查找包含一个或多个关键字的文件,这些关键字与作为参数传入的关键字列表中的任何内容相匹配。它可能有一个明显的解决方案,但我看不到它。

提前致谢。

4 个答案:

答案 0 :(得分:0)

是否要查找所有File个对象,Keywords中的任何元素都存在于您传递给方法的关键字集合中?

在查询中对Keyword类执行任何操作显然都是禁忌。正如您的错误所示,它只能翻译原始类型。

var names = keywords.Select(x => x.Name).ToList();

return Context.Files.Where(x => keywords.Select(y => y.Name).Intersect(names).Any());

答案 1 :(得分:0)

也许既然你在使用Linq解决这个问题时遇到了麻烦,那么你应该从你可以做的事情开始。例如一些简单的循环。一旦你有了这个工作,你就可以转到Linq查询。

IEnumerable<File> FindByKeywords(IEnumerable<Keyword> keywords)
{
    var foundFiles = new List<File>();

    foreach (File file in Context.Files)
    {
        foreach (string fileWord in file)
        {
            foreach (string keyword in keywords)
            {
                if (fileWord == keyword)
                {
                    foundFiles.Add(file);
                    break;
                }
            }
        }
    }

    return foundFiles;
}

答案 2 :(得分:0)

我可以先建立索引,然后查询索引:

IDictionary<string, List<File>> BuildIndex(IEnumerable<File> files)
{
    var index = new Dictionary<string, List<File>>();

    foreach (File file in files)
    {
        foreach (string keyword in file.Keywords.Select(k => k.Name))
        {
            if (!index.ContainsKey(keyword))
                index[keyword] = new List<File>();
            index[keyword].Add(file);
        }
    }

    return index;
}

IEnumerable<File> FindByKeywords(IEnumerable<Keyword> keywords)
{
    var index = BuildIndex(Context.Files);

    return keywords
        .Where(k => index.ContainsKey(k.Name))
        .SelectMany(k => index[k.Name])
        .Distinct()
        .ToList();
}

答案 3 :(得分:0)

据我所知,您正在寻找关键词集合中所有关键字的所有文件。

我会这样写:

IEnumerable<File> FilesThatContainsAnyKeyword(
        IEnumerable<File> files, // IQueryable<File>?
        IEnumerable<Keyword> keywords)
{
    var keywordSet = new HashSet<string>(keywords.Select(k => k.Name));
    return files.Where(f => 
        f.Keywords.Any(k => keywordSet.Contains(k.Name))
    );
}

然后叫它:

IEnumerable<File> FindByKeywords(IEnumerable<Keyword> keywords)
{
    return FilesThatContainsAnyKeyword(Context.Files, keywords);
}

由于无法直接比较关键字对象的相等性,因此您必须按身份(Name)对它们进行比较。