Expand in a Projection (Select) for WCF Data Services (OData)

纵然是瞬间 提交于 2019-12-08 15:40:05

问题


Say I have an OData query that looks like this (My actual query is much more complex):

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

This works fine. Except that the Address object has a sub object on it (StateRef). Since StateRef does a look-up on the State table, it is returned as null.

To illustrate, here is an example of how the address object Address might look:

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

The StateRef object has the name of the state on it, but also has some other important State properties (maybe state bird?)

So, what I am wondering is, do I have to now create a "sub projection" for z.SubOrder.Addresses that contains all 46 attributes just so that I can access the PrimaryState item? (I Hope NOT)

Aside from being way more coding, it also means I have to use anonymous types. Which makes my mapping have to be by hand (instead of using AutoMapper).

So what I am looking for is a way to "Expand" the StateRef inside the projection?

Something like this:

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

Trying this give this error:

Invalid anonymous type member declarator. Anonymous type members must be declared with a member assignment, simple name or member access.

Update: Here is an example query to illustrate what I am asking about:

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

Run that against "data.stackexchange.com/stackoverflow/atom". You will see that Comments has a Post object that returns null.

I need that to return the values inside of it.

Note: I know I can manually type all of them out into a "sub" projection. Read above for why I do not want that.


回答1:


It is certainly possible to do that. For a proof of concept try executing this:

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

The correct usage of expand is like this:

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

I don't know why the writers of the library have decided to disallow using expand with projections, but as the above proof of concept shows, it is certainly possible to do so.

If you don't mind receiving the entire user and making the projection after that, you can go with the second example. Else you can write your own helpers which will produce the URI from the first example, execute them, and add the projection after that.




回答2:


You don't have to create a sub-projection which lists out all 46 attributes, e.g.

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

Not exactly the object graph I imagine you're after.

This aside, one can spend a lot of time trying to write a LinQ expression that will generate the correct OData query, we've found that it is much more time effecient to create your own OData query class with Expand, Filter, Select properties etc. i.e. go straight to writing OData queries instead of trying to craft LinQ queries.




回答3:


You can do,

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

That would result in the request,

http://data.stackexchange.com/stackoverflow/atom/Users()?$top=10&$expand=Comments&$select=Id,Reputation,Comments/Id




回答4:


The Expand is done on the query. See How to: Load Related Entities (WCF Data Services)

You want something like:

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



回答5:


You can select particular properties from subObjects.

e.g. in the example for StackOverflow, I can execute following query successfully in LINQPad.

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

In your case, you can write a query like this:

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


来源:https://stackoverflow.com/questions/14782342/expand-in-a-projection-select-for-wcf-data-services-odata

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!