LINQ列表包含。

6

我正在使用ArangoDB,并查询名为movies的集合。其数据结构是这样的,categories是字符串列表。

public class movies
{
    [DocumentProperty(Identifier = IdentifierType.Key)]
    public string Key;
    public List<string> categories;
    public string desc;
    public string img;
    public List<vod_stream> streams;
    public string title;
};

以下是查询语句:

var result = db.Query<movies>()
            .Where(p => p.categories.Contains(id));

传递id作为参数,我需要检索所有分类与此id匹配的电影。

然而,上面的代码无法正常工作,因为result返回集合中所有电影。

foreach (movies mov in result)
{
    if (mov.categories.Contains(id) == false)
    { continue; }

    // do something here
}

奇怪的是,当我循环遍历结果中的项时,对于某些项,相同的函数确实返回false。但它在Linq语句中就是不起作用。
有人知道我的查询语句有什么问题吗?

我不明白为什么第二段代码可以工作而前一段不能。你确定提供了完整的代码吗?也许你忘记了一些“!”运算符。无论如何,你可以将第二个条件缩短为if(!mov.categories.Contains(id)) - MakePeaceGreatAgain
包含对列表中对象的Equals方法的调用。如果您的类“movies”没有正确覆盖Equals方法,它将默认返回false,除非它是同一个对象(即内部引用编号相同)。 - Chrisi
@Chrisi - categories 是一个字符串列表,所以我不认为这是情况。 - Gilad Green
这两个片段几乎没有任何共同之处。第一个是数据库查询,第二个甚至不是查询,只是对列表的迭代。你想做什么?查找属于特定类别的所有电影吗?第一个片段生成的查询是什么? - Panagiotis Kanavos
@PanagiotisKanavos 没错,我想要返回属于特定类别的所有电影结果。第一个片段中的查询生成了数据库集合中的每个电影,这不是我想要的。 - Darren
显示剩余3条评论
3个回答

5

要在ArangoDB LINQ提供程序中使用AQL函数,您应该使用ArangoDB.Client.AQL的静态方法。

对于您的用例,您可以使用in AQL函数:

var result = db.Query<movies>()
                .Where(p => AQL.In(id, p.categories))
                .ToList();

这句话的意思是:
for `p` in `movies`  filter  @P1 in `p`.`categories`  return   `p`

ArangoDB LINQ提供程序目前不支持像List这样的C#数据结构中的内置方法。


哇哦!我从来没有想到过...ArangoDB客户端的作者已经发言了!这绝对是最佳解决方案,尽管我在AQL世界里确实有些迷茫。 xD - Darren
@Darren AQL中的in用于检查成员是否存在,类似于c#中的Contains - raoof hojat
感谢您提供答案! - Darren

3
LINQ可能是一个奇怪的东西。如果你习惯于使用LINQ来操作对象,那么你的代码似乎没有问题。然而,你的代码并不起作用是因为它将LINQ转换为数据库查询。
工作的代码与不工作的代码的区别在于,通过对数据库查询的数据进行foreach循环,你正在将数据材料化并恢复回到对象中。
我查看了这个客户端文档,因为我不熟悉它,有一点引起了我的注意:
int age =  db.Query<Person>()
                  .Where(p => AQL.Contains(p.Name, "raoof"))
                  .Select(p => p.Age)
                  .FirstOrDefault();

请注意,AQL.Contains - 它类似于 LINQ-to-SQL 支持 SQLServer 数据库函数的方式。因此,我建议存在一个 AQL.<something> 方法可以实现您想要的功能。不幸的是,他们的文档并不是最好的,我很难找到您需要的内容。您可以尝试以下操作:
var result = db.Query<movies>()
        .Where(p => AQL.Contains(p.categories,id));

问题中的第二个片段甚至不是一个LINQ查询。等价的LINQ查询与数据库查询 result.Where(p => p.categories.Contains(id)) 看起来完全一样。它仍然可能给出不同的结果,因为.NET字符串比较区分大小写,而数据库通常使用不区分大小写的排序规则。 - Panagiotis Kanavos
@PanagiotisKanavos 我不确定我理解你的意思。它似乎并没有要求对我的答案进行澄清,所以有点不相关。 - Jamiec
这是一条注释。并非所有的注释都是在请求澄清。这并不意味着它们无关紧要。 - Panagiotis Kanavos
@PanagiotisKanavos,看起来这应该是对问题的评论。它与我的答案无关! - Jamiec
我同意,他们的文档非常有限。:( - Darren

-1

当我添加了一个快速代码时,它确实起作用了。

public void GetMoviesByCategory()
    {

        List<Movies> movies = new List<Movies>();
        movies.Add(new Movies(){moviename = "A", category = new List<String>(){"1","2"}});
        movies.Add(new Movies(){moviename = "B", category = new List<String>(){"2","3"}});
        movies.Add(new Movies(){moviename = "C", category = new List<String>(){"3","4"}});
        movies.Add(new Movies(){moviename = "D", category = new List<String>(){"1"}});
        movies.Add(new Movies(){moviename = "E", category = new List<String>(){"4"}});
        movies.Add(new Movies(){moviename = "F", category = new List<String>(){"1","2","4"}});
        var result = movies.Select(m => m).Where(p => p.category.Contains("1")).ToList();

        foreach(var movie in result){
            Console.WriteLine(movie.moviename);
        }
    }
    public class Movies{

        public Movies(){}
        public string moviename {get;set;}
        public List<string> category {get;set;}
    }

2
这是直接使用 LINQ 操作对象。而 OP 则是使用 LINQ 实现对数据库的操作。这是完全不同的事情。 - Jamiec

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接