在WCF数据服务(OData)的投影(选择)中展开



假设我有一个OData查询,它看起来像这样(我的实际查询要复杂得多):

Orders.Select(z => new { z.SubOrder.Addresses,
                         z.SubOrder.Cost,
                         z.SubOrder.SubOrderId, 
                         z.Sequence});

这很好用。除了Address对象上有一个子对象(StateRef)。由于StateRef在State表上进行查找,因此返回为null。

为了说明这一点,这里有一个地址对象address的外观示例:

Address:
    string         Street 1
    string         Street 2
    StateRef       PrimaryState
    string         City
    // ... 42 other string attributes not shown ...

StateRef对象上有状态的名称,但也有一些其他重要的状态属性(可能是状态鸟?)

所以,我想知道的是,我现在是否必须为z.SubOrder.Addresses创建一个包含所有46个属性的"子投影",这样我才能访问PrimaryState项?(我希望不要

除了编码更多之外,这也意味着我必须使用匿名类型。这使得我的映射必须手动(而不是使用AutoMapper)。

所以我想要的是一种在投影中"扩展"StateRef的方法

类似这样的东西:

Orders.Select(z => new { z.SubOrder.Addresses.Expand("PrimaryState"),
                         z.SubOrder.Cost,        ^
                         z.SubOrder.SubOrderId,  |
                         z.Sequence});           |
                                                 |
// This is not allowed by the compiler ----------+

尝试此操作会出现以下错误:

无效的匿名类型成员声明符。匿名类型成员必须使用成员分配、简单名称或成员访问权限声明。

更新:下面是一个示例查询来说明我所询问的内容:

Users.Take(10).Select(x=>new { x.Id, x.Reputation, x.Comments})

对"data.stackeexchange.com/stackoverflow/atom"运行该操作。您会看到Comments有一个返回null的Post对象。

我需要它来返回里面的值。

注意:我知道我可以手动将所有这些输入到"子"投影中。阅读上面我为什么不想那样

这样做当然是可能的。对于概念验证,请尝试执行以下操作:

var uri = new Uri( "http://data.stackexchange.com/stackoverflow/atom/Users()?$top=10&$expand=Comments/Post&$select=Id,Reputation,Comments/" );
entities.Execute<User>( uri, "GET", false ).Select( x => new { x.Id, x.Reputation, x.Comments } );

expand的正确用法如下:

entities.Users.Expand( "Comments/Post" ).Take( 10 ).ToArray();

我不知道为什么图书馆的作者决定不允许使用带投影的展开,但正如上面的概念证明所示,这样做当然是可能的

如果你不介意接收整个用户并在那之后进行投影,你可以使用第二个例子。否则,您可以编写自己的助手,它将从第一个示例中生成URI,执行它们,然后添加投影。

您不必创建列出所有46个属性的子投影,例如

(from u in Users
 select new 
    {
    u.Id, u.Reputation,Comments = ( from c in u.Comments 
                                    select new YourClass {comment = c, 
                                                          post= c.Post})
    }
)
.Take(10)

.....

public Class YourClass
    {
    public Comment comment {get;  set;}
    public Post post {get;set;}
    }

不完全是我想象中的对象图。

除此之外,人们可能会花费大量时间来尝试编写一个LinQ表达式,该表达式将生成正确的OData查询,我们发现,使用Expand、Filter、Select属性等创建自己的OData询问类会更省时,即直接编写OData查询而不是编写LinQ查询。

你可以做,

Users.Take(10).Select(x=>new { Id = x.Id, Reputation = x.Reputation, Comments = x.Comments.Select(c =>c.Id) })

这将导致请求,

https://data.stackexchange.com/stackoverflow/atom/Users()$top=10&expand=注释&select=Id,信誉,评论/Id

您可以从子对象中选择特定的属性。

例如,在StackOverflow的例子中,我可以在LINQPad中成功执行以下查询。

Users
.Take (10)
.Select(x => new {x.Id, x.Reputation, CommentsText = x.Comments.Select(c => c.Text)})

在您的情况下,您可以编写这样的查询:

Orders.Select(z => new { StateName = z.SubOrder.Addresses.Select(a => a.PrimaryState),
                     z.SubOrder.Cost,        
                     z.SubOrder.SubOrderId,
                     z.Sequence});   

Expand在查询中完成。请参阅如何:加载相关实体(WCF数据服务)

你想要类似的东西:

Orders
  .Expand("StateRef")
  .Select(z => new { ... } );

最新更新