【问题标题】:How do I use linq to do a WHERE against a collection object (using Netflix data source)如何使用 linq 对集合对象执行 WHERE(使用 Netflix 数据源)
【发布时间】:2010-09-18 16:23:53
【问题描述】:

我正在使用 LinqPad 通过查询 NetFlix OData 源来学习 Linq。

(顺便说一句,我知道他们已经在 SO 上提出了类似的问题......没有帮助我)。

这是我得到的查询,非常棒。

from x in Titles
//where x.Rating=="PG"
where x.Instant.Available==true
where x.AverageRating>=4.0
//where x.Rating.StartsWith("TV")
//where x.Genres.First (g => g.Name.Contains("Family") ) //(from y in Genres where y.Name.Contains("Family") select y)
//where x.Genres.First (g => g.Name=="")
//orderby x.Name
orderby x.AverageRating descending
//select x
//)
select new {x.Name, x.Rating, x.AverageRating, x.ShortSynopsis}

(请原谅所有的 cmets...这证明了我正在试验的事实,并且我将根据各种需要更改查询)。

有两件事我想不通。

首先。假设我只想返回前 10 个结果。

其次(也是最重要的)。我想按流派的部分字符串进行过滤。每个标题都包含一个流派集合。我只想显示名称包含某个字符串(如“家庭”)的流派。使用包含“firstFilter”和“secondFilter”的标题更好地过滤。

基本上,我想按流派过滤,但我不知道该怎么做,因为 Title 包含它自己的 Genres 集合,我不知道如何只返回集合中一种或多种流派的标题.

感谢您的帮助!

ps...Netflix OData 源似乎不支持 Any 运算符。

赛斯

【问题讨论】:

标签: c# vb.net linq odata linqpad


【解决方案1】:

要返回前 10 个结果,请将上面的代码用括号括起来,并在末尾添加一个 .Take(10)

var foo = ( from x in Titles... ).Take(10);

目前没有办法在 C# 中使用查询语法。

至于类型过滤器,正如 klabranche 指出的那样,oData 不支持许多可以在本地使用常规 IEnumerable 或 IQueryable 的相同 Linq 构造。

klabranche 的解决方案不支持包含。但是,它确实需要对服务器进行 2 次往返以获得结果。 (请参阅我对他的回答的评论,了解为什么这似乎是必要的)

这是一种替代方法,它往返于服务器以获取数据,然后在本地处理该数据。由于某些查询在本地运行,因此您可以使用 string.Contains、“或”子句和其他优点。

这种方法的缺点是它通过网络检索的数据多于回答查询所需的数据。另一方面,它很容易理解并且有效。

当我结合“家庭”和“孩子”时,它返回 21 个结果。

var oDataQuery = from x in Titles
                 where x.AverageRating >= 4
                    && x.Instant.Available==true       
                 orderby x.AverageRating descending
                 select new {x.Name, x.Rating, x.AverageRating, x.ShortSynopsis, x.Genres};

var localQuery = from o in oDataQuery.ToList()
                 where o.Genres.Any(g => g.Name.Contains("Family"))
                    && o.Genres.Any(g => g.Name.Contains("Children"))
                 select new {o.Name, o.Rating, o.AverageRating, o.ShortSynopsis };

localQuery.Dump();

【讨论】:

  • Slaggg,绝对精彩的答案。回答了我问的两个问题和我没有问的第三个问题。多“where”语句困扰着我,但不再是了。干得好。
  • Linqpad 报告 Any 运算符的不受支持的异常。我猜 Netflix OData 源不支持它。你知道没有 Any 操作符的另一种做同样事情的方法吗?
  • klabranche 指出 odata 不支持我们在本地习惯的所有内容。我已经修改了答案以在 odata 范围内工作。
  • 干得好。我正在学习 LINQ atm 并认为有更好的方法。很高兴看到我帮助你到达那里。 :-)
【解决方案2】:

OData 和 Netflix API 支持 Take() 和 Contains() 方法:

from t in Titles
where t.Name.Contains("Matrix")
select t

(from t in Titles
where t.Name.Contains("Matrix")
select t).Take(10)

【讨论】:

  • 是的,虽然我认为一些 OData 实现限制了一些 take/skip 和 contains 以防止查询影响性能。
  • 有趣 - 我不知道。
【解决方案3】:

要获得前 10 个:

(from x in Titles
where x.Instant.Available==true 
where x.AverageRating>=4.0 
orderby x.AverageRating descending 
select new {x.Name, x.Rating, x.AverageRating, x.ShortSynopsis}
).Take(10)

按单一类型过滤(不是你想要的......):

from g in Genres
from t in g.Titles 
where g.Name == "Horror" 
where t.Instant.Available==true
where t.AverageRating >=4.0
orderby t.AverageRating descending 
select new {t.Name, t.Rating, t.AverageRating, t.ShortSynopsis}

但是,您想要多个流派但 OData 不支持 Select Many queries,这就是包含失败或尝试 OR 流派名称的原因。

以下失败因为包含返回很多...

var q1 = from g in Genres
from t in g.Titles 
where g.Name.Contains("Horror")
where t.Instant.Available==true
where t.AverageRating >=4.0
orderby t.AverageRating descending 
select new {t.Name, t.Rating, t.AverageRating, t.ShortSynopsis};

要按多种类型进行过滤,我发现您可以使用Concat or Union query(在 LinqPad 中请务必更改为 C# 语句而不是表达式):

var q1 = from g in Genres
from t in g.Titles 
where g.Name=="Horror"
where t.Instant.Available==true
where t.AverageRating >=4.0
orderby t.AverageRating descending 
select new {t.Name, t.Rating, t.AverageRating, t.ShortSynopsis};

var q2 = from g in Genres
from t in g.Titles 
where g.Name=="HBO"
where t.Instant.Available==true
where t.AverageRating >=4.0
orderby t.AverageRating descending 
select new {t.Name, t.Rating, t.AverageRating, t.ShortSynopsis};

var concat = q1.ToList().Concat(q2);
//var union = q1.Union(q2);

通过合并这两个查询,它将删除重复项,但这些是您想要的如果我理解正确,您想要只在这两种类型中的电影?

在这种情况下,您将需要使用将返回所有记录的 Concat。

现在您只需要多次查找查询中的记录即可获得结果:

var results = from c in concat
group c by c.Name into grp
where grp.Count() > 1
select grp;

【讨论】:

  • 当我尝试在 LinqPad 中运行它时,我得到“不支持方法 'Concat'。”
  • 我可以通过分别运行每个查询并在内存中执行 concat 来运行它 - 将“var concat”行更改为“var concat = q1.ToList().Concat(q2.ToList ());"。所写的查询返回 0 个结果。
  • 它对我有用(实际上在 LinqPad 中完成了上述操作)。我使用的是最新的 linqPad 版本。你?
  • 嗯。我是 v4.26.2。出于好奇,在 sql 选项卡上显示了多少个 odata 查询?我只能使用 2 个单独的查询来运行这种方法。
  • 尝试 var concat = q1.ToList().Concat(q2); concat.Dump();
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-05
  • 1970-01-01
  • 2012-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多