【问题标题】:Linq List ContainsLinq 列表包含
【发布时间】:2017-09-12 08:07:47
【问题描述】:

我正在使用 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 语句中不起作用。

有人知道我的查询语句有什么问题吗?

【问题讨论】:

  • 我不明白为什么第二个代码有效,而前一个无效。你确定你提供了确切的代码吗?也许你忘记了一些!-operator。无论如何,您可以将第二个条件缩短为if(!mov.categories.Contains(id))
  • 包含调用列表中对象的 Equals 方法。如果您的类 movies 没有正确覆盖 Equals,它将默认返回 false,除非它的对象相同(即内部引用编号相同)。
  • @Chrisi - categories 是一个字符串列表,所以我认为不是这样
  • 我已经更新了我的问题,以便更清楚
  • 这两个 sn-ps 几乎没有共同点。第一个是 database 查询,第二个甚至不是查询,它只是一个列表的迭代。 你想做什么?查找属于特定类别的所有电影?第一个sn-p生成的查询是什么?

标签: c# linq arangodb


【解决方案1】:

要在 ArangoDB LINQ 提供程序中使用 AQL Functions,您应该使用 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 提供程序目前不支持用于 c# 数据结构(如 List)的内置方法

【讨论】:

  • 哇哦!没想到……ArangoDB客户端的作者发话了!这绝对是 The FIX,尽管我真的很迷失在 AQL 世界中。 xD
  • @Darren AQL in 用于检查成员是否存在,如c#中的Contains
  • 感谢您提供答案!
【解决方案2】:

LINQ 可能是一头奇怪的野兽。如果您习惯于对直接对象使用 LINQ,那么您的代码似乎没有任何问题。但是,您的代码不起作用将 LINQ 转换为数据库查询。

有效的区别在于,通过对数据库查询的数据执行foreach,您可以将数据具体化并恢复为对象。

我看了docs做arrangodb客户端,因为我不熟悉,有点突出:

int age =  db.Query<Person>()
                  .Where(p => AQL.Contains(p.Name, "raoof"))
                  .Select(p => p.Age)
                  .FirstOrDefault();

注意AQL.Contains - 它类似于 LINQ-to-SQL 用于支持 SQLServer 的数据库功能的方式。所以我建议有一个AQL.&lt;something&gt; 方法可以做你想做的事。不幸的是,他们的文档不是最好的,我正在努力寻找你需要的东西。您可以尝试以下方式

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

【讨论】:

  • 问题中的第二个 sn-p 甚至不是 LINQ 查询。等效的 LINQ 查询看起来与数据库查询 result.Where(p =&gt; p.categories.Contains(id)) 相同。它仍然可能给出不同的结果,因为 .NET 字符串比较区分大小写,而数据库通常使用不区分大小写的排序规则
  • @PanagiotisKanavos 我不确定我是否听懂了你的意思。它似乎没有要求澄清我的答案,所以似乎有点无关紧要。
  • 这是一条评论。并非所有 cmets 都要求澄清。这并不意味着它们无关紧要
  • @PanagiotisKanavos 在这种情况下,它似乎应该是对问题的评论。它与我的答案无关!
  • 我同意,他们的文档非常有限.. :(
【解决方案3】:

当我添加一个快速代码时,这确实有效

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;}
    }

【讨论】:

  • 这是直接将 linq 用于对象。 OP 正在对数据库使用 Linq 实现。这是完全不同的事情
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-19
  • 1970-01-01
相关资源
最近更新 更多