如何使用linq对集合对象执行WHERE(使用Netflix数据源)

时间:2010-09-18 16:23:54

标签: c# vb.net linq odata linqpad

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

(顺便说一下,我知道他们已经是一个类似的问题了......对我没有帮助)。

这是我工作的查询很棒。

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}

(原谅所有评论......这是我正在试验的事实的证明,我会根据各种需要改变查询。)

有两点我无法弄清楚。

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

第二(也是最重要的)。我想通过该类型的部分字符串进行过滤。每个标题都包含一个Genres集合。我想只显示名称包含某个字符串的类型(如“家庭”)。甚至更好的过滤使用标题,其中genre.name.contains“firstFilter”和“secondFilter”。

基本上,我想根据类型进行过滤,我无法弄清楚怎么做,因为Title包含自己的Genres集合,我无法弄清楚如何仅返回集合中一个或多个类型的标题

感谢您的帮助!

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

赛斯

3 个答案:

答案 0 :(得分:4)

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

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

目前无法在C#中使用查询语法。

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

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();

答案 1 :(得分:1)

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)

答案 2 :(得分:1)

获得前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;