问题
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