2013-02-08 6 views
10

sagen, dass ich eine OData Abfrage haben, die wie folgt aussieht (Meine eigentliche Abfrage ist viel komplexer):in einer Projektion erweitern (Auswahl), WCF Data Services (OData)

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

Dies funktioniert gut. Nur dass das Address-Objekt ein Sub-Objekt enthält (StateRef). Da StateRef in der State-Tabelle nachschlägt, wird es als Null zurückgegeben.

Zur Veranschaulichung hier ein Beispiel dafür, wie die Adressobjekt Adresse aussehen könnte:

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

Das StateRef Objekt den Namen des Staates auf sich hat, sondern hat auch einige andere wichtige staatliche Eigenschaften (vielleicht Zustand Vogel?)

Also, was ich frage mich ist, muss ich jetzt eine "Unterprojektion" für z.SubOrder.Addresses erstellen, die alle 46 Attribute enthält, nur so dass ich auf den PrimaryState Artikel zugreifen kann? (Ich hoffe nicht)

Abgesehen davon, viel mehr Codierung, bedeutet es auch, dass ich anonyme Typen verwenden müssen. Das macht mein Mapping von Hand (anstelle von AutoMapper).

Also was ich suche ist eine Möglichkeit, die StateRef innerhalb der Projektion zu "erweitern"?

Etwas wie folgt aus:

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

Der Versuch, das diesen Fehler geben:

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

Update: Hier ist ein Beispiel Abfrage zu veranschaulichen, was ich fragen nach:

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

Führen Sie diese gegen "data.stackexchange.com/stackoverflow/atom". Sie werden sehen, dass Comments ein Post-Objekt hat, das null zurückgibt.

Ich brauche das, um die Werte darin zurückzugeben.

Hinweis: Ich weiß, dass ich sie alle manuell in eine "Unterprojektion" eingeben kann. Lesen Sie oben, warum ich das nicht will.

+0

Seit erweitern scheint nur auf dem ersten Kind zu arbeiten, können Sie Ihre Abfrage umkehren? Also für Ihr SO-Beispiel beginnen Sie mit Kommentaren, z. Kommentare.Expand (c => c.User) .Expand (c => c.Post) .Nehmen (10) – Phil

+0

@Phil, Ach, nein. Dieses Beispiel ist einfach, aber meine eigentliche Abfrage ist sehr komplex und hat mehrere "Unterabschnitte". – Vaccano

+0

Die Verbindung ist tot. –

Antwort

7

Es ist sicherlich möglich, das zu tun:

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

In Ihrem Fall können Sie eine Abfrage so schreiben. Für ein Proof of Concept versuchen Ausführung dieses:

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

Die korrekte Verwendung von erweitern ist wie folgt:

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

Ich weiß nicht, warum die Autoren der Bibliothek entschieden haben, nicht zulassen Verwendung erweitern mit Projektionen, aber wie der oben genannte proof of concept zeigt, ist dies sicherlich möglich.

Wenn es Ihnen nichts ausmacht, den gesamten Benutzer zu empfangen und danach die Projektion zu machen, können Sie mit dem zweiten Beispiel fortfahren. Andernfalls können Sie eigene Helfer schreiben, die den URI aus dem ersten Beispiel erzeugen, ausführen und danach die Projektion hinzufügen.

+0

Sehr, sehr interessant .... Also der Server erlaubt es, nur nicht die Client-Bibliothek. Ich denke, das beantwortet meine Frage. – Vaccano

0

Die Expand ist auf die Abfrage erfolgt. Siehe How to: Load Related Entities (WCF Data Services)

Sie wollen so etwas wie:

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

Das gibt die folgende Ausnahme: * NotSupportedException: Die Projektion kann nicht erstellt werden, wenn für dieselbe Abfrage eine explizite Erweiterung angegeben wurde. * – Vaccano

+0

Zeigen Sie den gesamten Code für die Abfrage Bestellungen an. Sie können Kommas im Argument .Expand für mehrere Erweiterungen verwenden. –

+0

Sie können jedoch keine expand-Klausel und eine select-Klausel haben. Bei jeder Abfrage und jedem Endpunkt. Ich habe Expand verwendet, weil das die Funktionalität ist, nach der ich suche. Aber ich war noch nie in der Lage, einen Expand und einen Select zu kombinieren. Wenn Sie bitte ein Beispiel (gegen Netflix oder StackOverFlows Feeds) posten können. – Vaccano

2

Sie müssen keine Untervorsprung schaffen, die alle 46 Attribute auflistet, z.B.

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

Nicht genau das Objektdiagramm, das ich mir vorstellen, Sie sind danach.

Abgesehen davon, dass man viel Zeit damit verbringen kann, einen LinQ-Ausdruck zu schreiben, der die korrekte OData-Abfrage generiert, haben wir festgestellt, dass es viel effizienter ist, mit Expand, Filter eine eigene OData-Abfrageklasse zu erstellen , Wählen Sie Eigenschaften usw., dhgehen Sie direkt zum Schreiben von OData-Abfragen, anstatt zu versuchen, LinQ-Abfragen zu erstellen.

+0

Ich wusste nicht, dass du das kannst. Dies löst die Hälfte meines Problems.(Ich habe immer noch einen anonymen Typ, für den ich AutoMapper nicht verwenden kann). Wenn niemand mit einer vollständigen Antwort antwortet, wähle ich deine aus. – Vaccano

+0

Sie könnten einen konkreten Typ anstelle des anonymen Typs erstellen. z.B. Klasse MyProjection {int Id {...}, ...}; wähle newProjection {Id = u.Id ...} – Phil

+0

Wie Phil sagt, kann der anonyme Typ ersetzt werden. Ich habe das Code-Snippet oben erweitert, um zu zeigen, wie der verschachtelte anonyme Typ ersetzt werden kann. –

0

Sie können bestimmte Eigenschaften von Unterobjekten auswählen.

z.B. Im Beispiel für StackOverflow kann ich die folgende Abfrage in LINQPad erfolgreich ausführen.

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

Dies ist im Grunde eine andere Projektion, ich am Ende mit anonymen Typen. – Vaccano