【问题标题】:Expand in a Projection (Select) for WCF Data Services (OData)在 WCF 数据服务 (OData) 的投影中展开(选择)
【发布时间】:2019-07-07 01:46:41
【问题描述】:

假设我有一个看起来像这样的 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 对象上面有州的名称,但也有一些其他重要的州属性(也许是州鸟?)

所以,我想知道的是,我现在是否必须为包含所有 46 个属性的 z.SubOrder.Addresses 创建一个“子投影”,以便我可以访问 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.stackexchange.com/stackoverflow/atom”运行它。您将看到 Comments 有一个返回 null 的 Post 对象。

我需要它来返回其中的值。

注意:我知道我可以手动将它们全部输入到“子”投影中。阅读上面的内容,了解我不希望这样做的原因。

【问题讨论】:

  • 由于 Expand 似乎只适用于第一个孩子,您可以反转您的查询吗?因此,对于您的 SO 示例,请从评论开始,例如Comments.Expand(c => c.User).Expand(c => c.Post).Take(10)
  • @Phil,唉,不。这个例子很简单,但我的实际查询很复杂,有几个“子部分”。
  • 链接已失效。

标签: c# .net exception odata wcf-data-services


【解决方案1】:

当然可以这样做。要进行概念验证,请尝试执行以下操作:

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,执行它们,然后添加投影。

【讨论】:

  • 非常非常有趣......所以服务器允许它,而不是客户端库。我认为这回答了我的问题。
【解决方案2】:

您不必创建列出所有 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;}
    }

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

除此之外,人们可能会花费大量时间来尝试编写将生成正确 OData 查询的 LinQ 表达式,我们发现使用 Expand、Filter、选择属性等,即直接编写 OData 查询,而不是尝试制作 LinQ 查询。

【讨论】:

  • 我不知道你能做到这一点。这解决了我一半的问题。 (我仍然有一个无法使用 AutoMapper 的匿名类型)。如果没有人回答完整的答案,那么我会选择你的。
  • 您可以创建一个具体类型来代替匿名类型。例如类 MyProjection{ int Id{...}, ... };选择新的 MyProjection { Id = u.Id ... }
  • 正如菲尔所说,可以替换匿名类型。我已经扩展了上面的代码 sn-p 来展示如何替换嵌套的匿名类型。
【解决方案3】:

你可以的,

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=Comments&$select=Id,Reputation,Comments/Id

【讨论】:

    【解决方案4】:

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

    例如在 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});   
    

    【讨论】:

    • 这基本上是在做另一个投影,我最终得到了匿名类型。
    【解决方案5】:

    Expand 在查询中完成。见How to: Load Related Entities (WCF Data Services)

    你想要这样的东西:

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

    【讨论】:

    • 这给出了这个异常:NotSupportedException: Cannot create projection while there is an explicit expansion specified on the same query.
    • 请显示订单查询的完整代码。您可以在 .Expand 参数中使用逗号进行多个扩展。
    • 但是你不能有一个扩展子句和一个选择子句。在任何查询和任何端点上。我使用 Expand 是因为这是我正在寻找的功能。但是我从来没有能够将扩展和选择结合起来。如果可以,请发布一个示例(针对 Netflix 或 StackOverFlows 提要)。
    • 阅读示例中的链接它有一个示例。
    • 这是一个示例查询。 Users.Take(10).Select(x=&gt;new { x.Id, x.Reputation, x.Comments}) 对“data.stackexchange.com/stackoverflow/atom”运行它请注意,“评论”对象上有一个“帖子”对象。那返回空值。我想要一种扩展它的方法(无需手动设置投影)
    猜你喜欢
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多