动态Linq查询问题

时间:2010-04-22 02:40:19

标签: c# linq

我试图查询Netflix OData Feed。我有以下查询在LinqPad中正常工作:

from g in Genres
from t in g.Titles
where g.Name == "Horror" && t.AverageRating == 2 && t.ReleaseYear == 2004
select t

但是,当我将其移动到我的Silverlight应用程序时,用户选择要搜索的内容,因此我可能会或可能不会拥有所有参数。既然如此,我需要在运行时构造查询。我看过动态查询的东西,这样做会很好......我遇到的问题是我需要一个初始可接受的查询来附加,但这不会飞:

from g in Genres
from t in g.Titles
select t;

任何额外的想法将不胜感激。 提前致谢

2 个答案:

答案 0 :(得分:1)

如何以旧式,非动态的方式添加过滤器?

var genresQuery = from g in Genres select g;
if ( !string.IsNullOrEmpty( name ) ) genresQuery = genresQuery.Where( g => g.Name == name );

var titlesQuery = from t in genresQuery select t;
if ( !string.IsNullOrEmpty( rating ) ) titlesQuery = titlesQuery.Where( t => t.AverageRating == rating );
if ( !string.IsNullOrEmpty( year ) ) titlesQuery = titlesQuery.Where( t => t.ReleaseYear == year );

答案 1 :(得分:1)

您没有 使用动态查询语法执行此操作,但您可以。

你真的有两个查询,所以你应该建立它们。你可以一次完成所有这些,但是你需要在不同的地方使用两个特定的where子句,一个用于Genres,一个用于标题。请考虑以下模仿您情况的示例。

class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Bar> Bars { get; set; }
}

class Bar
{
    public string Color { get; set; }
}

...

List<Foo> foos = new List<Foo>()
{
    new Foo() { Id = 1, Name = "Apple", Bars = new List<Bar> () { new Bar() { Color = "Red"}, new Bar() { Color="Green"}} },
    new Foo() { Id = 2, Name = "Orange", Bars = new List<Bar> () { new Bar() { Color = "Orange"},new Bar() { Color="Red Orange"}} },
    new Foo() { Id = 3, Name = "Banana",Bars = new List<Bar> () { new Bar() { Color = "Yellow"},new Bar() { Color="Green"}} },
    new Foo() { Id = 4, Name = "Pear",Bars = new List<Bar> () { new Bar() { Color = "Green"},new Bar() { Color="Yellow"}} }
};

string fooName = "Apple";
string barColor = "Green";

var fooQuery = foos.AsQueryable();

if (!string.IsNullOrEmpty(fooName))
{
    string filter = string.Format("Name = \"{0}\"", fooName);
    fooQuery = fooQuery.Where(filter);
}

var barQuery = fooQuery.SelectMany(f => f.Bars);

if (!string.IsNullOrEmpty(barColor))
{
    string filter = string.Format("Color = \"{0}\"", barColor);
    barQuery = barQuery.Where(filter);
}

首先,它为Foos构建了一个查询。如果需要过滤(基于fooSearchName变量),它会生成Where子句并将其添加到查询中。之后,它成为返回Bar元素的查询的基础。同样的,如果它需要过滤,则会生成Where子句并将其添加到查询中。

不幸的是,由于在第一步评估了类型推断,因此无法在步骤上构建单个查询。如果您要说var query = foos.AsQueryable();,则查询已经评估为IQueryable<Foo>,因此在稍后的语句中添加SelectMany以选择Bars会失败,因为这需要查询为IQueryable<Bar>。< / p>

在这种情况下,你的手是强制性的,你必须一次构建查询,或者至少到最高和包括SelectMany的部分,最后的Where子句可以在以后添加。所以你可以这样做:

var query = foos.AsQueryable().Where(fooSearchClause).SelectMany(f => f.Bars);
// later
query = query.Where(barSearchClause);

或者您将查询构建为使用另一个查询的查询,如我的示例所示。

无论如何,根据我提供的术语,迭代最终查询会产生一个结果。更改任一搜索变量的内容将导致查询产生不同的结果。