Развернуть в Projection (Выбрать) для служб данных WCF (OData)

Скажем, у меня есть запрос OData, который выглядит следующим образом (мой фактический запрос гораздо сложнее):

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

Это отлично работает. За исключением того, что у объекта Address есть подобъект (StateRef). Поскольку StateRef выполняет поиск в таблице состояний, она возвращается как нулевая.

Для иллюстрации приведем пример того, как может выглядеть адрес объекта 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.stackexchange.com/stackoverflow/atom ". Вы увидите, что Комментарии имеют объект Post, который возвращает ноль.

Мне нужно, чтобы вернуть значения внутри него.

Примечание: я знаю, что могу вручную напечатать все их в "суб" проекции. Читайте выше, почему я этого не хочу.

Ответ 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 } );

Правильное использование расширения таково:

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

Не точно графический объект, который, как я полагаю, вам нужен.

В стороне, можно потратить много времени на то, чтобы написать выражение LinQ, которое будет генерировать правильный запрос OData, мы обнаружили, что гораздо эффективнее создавать собственный класс запросов OData с помощью Expand, Filter, Выберите свойства и т.д., Идите прямо к написанию запросов OData вместо того, чтобы пытаться обрабатывать запросы LinQ.

Ответ 5

Вы можете выбрать определенные свойства из объектов subObject.

например. в примере для 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});