本文转自:http://chris.eldredge.io/blog/2014/04/24/Composite-Keys/
In unserer Grundkonfiguration haben wir dem Modellersteller mitgeteilt, dass unsere Entität einen zusammengesetzten Schlüssel hat, der aus einer ID und einer Version besteht:
<span class="line-number">1 <span class="line-number">2 <span class="line-number">3 <span class="line-number">4 <span class="line-number">5 <span class="line-number">6 <span class="line-number">7 <span class="line-number">8 <span class="line-number">9 <span class="line-number">10 </span></span></span></span></span></span></span></span></span></span> Nach dem Login kopieren |
<code class="c#"><span class="line"><span class="k">public <span class="k">void <span class="nf">MapDataServiceRoutes<span class="p">(<span class="n">HttpConfiguration <span class="n">config<span class="p">) <span class="line"><span class="p">{ <span class="line"> <span class="kt">var <span class="n">builder <span class="p">= <span class="k">new <span class="n">ODataConventionModelBuilder<span class="p">(); <span class="line"> <span class="line"> <span class="kt">var <span class="n">entity <span class="p">= <span class="n">builder<span class="p">.<span class="n">EntitySet<span class="p"><<span class="n">ODataPackage<span class="p">>(<span class="s">"Packages"<span class="p">); <span class="line"> <span class="n">entity<span class="p">.<span class="n">EntityType<span class="p">.<span class="n">HasKey<span class="p">(<span class="n">pkg <span class="p">=> <span class="n">pkg<span class="p">.<span class="n">Id<span class="p">); <span class="line"> <span class="n">entity<span class="p">.<span class="n">EntityType<span class="p">.<span class="n">HasKey<span class="p">(<span class="n">pkg <span class="p">=> <span class="n">pkg<span class="p">.<span class="n">Version<span class="p">); <span class="line"> <span class="line"> <span class="c1">// snip <span class="line"><span class="p">} </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code> Nach dem Login kopieren |
Dies reicht aus, damit unser OData-Feed edit
und self
Links für jede einzelne Entität in einer Form wie:
<code>http://localhost/odata/Packages(Id='Sample',Version='1.0.0') </code>
Aber wenn wir zu dieser URL navigieren, erhalten wir nicht nur diese eine Entität per Schlüssel, sondern den gesamten Entitätssatz zurück.
Um das richtige Verhalten zu erhalten, benötigen wir zunächst eine Überschreibung auf unserem PackagesODataController, die eine einzelne Entitätsinstanz per Schlüssel abruft:
<span class="line-number">1 <span class="line-number">2 <span class="line-number">3 <span class="line-number">4 <span class="line-number">5 <span class="line-number">6 <span class="line-number">7 <span class="line-number">8 <span class="line-number">9 <span class="line-number">10 <span class="line-number">11 <span class="line-number">12 <span class="line-number">13 <span class="line-number">14 <span class="line-number">15 <span class="line-number">16 <span class="line-number">17 <span class="line-number">18 <span class="line-number">19 <span class="line-number">20 </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span> Nach dem Login kopieren |
<code class="c#"><span class="line"><span class="k">public <span class="k">class <span class="nc">PackagesODataController <span class="p">: <span class="n">ODataController <span class="line"><span class="p">{ <span class="line"> <span class="k">public <span class="n">IMirroringPackageRepository <span class="n">Repository <span class="p">{ <span class="k">get<span class="p">; <span class="k">set<span class="p">; <span class="p">} <span class="line"> <span class="line"> <span class="k">public <span class="n">IQueryable<span class="p"><<span class="n">ODataPackage<span class="p">> <span class="n">Get<span class="p">() <span class="line"> <span class="p">{ <span class="line"> <span class="k">return <span class="n">Repository<span class="p">.<span class="n">GetPackages<span class="p">().<span class="n">Select<span class="p">(<span class="n">p <span class="p">=> <span class="n">p<span class="p">.<span class="n">ToODataPackage<span class="p">()).<span class="n">AsQueryable<span class="p">(); <span class="line"> <span class="p">} <span class="line"> <span class="line"> <span class="k">public <span class="n">IHttpActionResult <span class="nf">Get<span class="p">( <span class="line"><span class="na"> [FromODataUri] <span class="kt">string <span class="n">id<span class="p">, <span class="line"><span class="na"> [FromODataUri] <span class="kt">string <span class="n">version<span class="p">) <span class="line"> <span class="p">{ <span class="line"> <span class="kt">var <span class="n">package <span class="p">= <span class="n">Repository<span class="p">.<span class="n">FindPackage<span class="p">(<span class="n">id<span class="p">, <span class="n">version<span class="p">); <span class="line"> <span class="line"> <span class="k">return <span class="n">package <span class="p">== <span class="k">null <span class="line"> <span class="p">? <span class="p">(<span class="n">IHttpActionResult<span class="p">)<span class="n">NotFound<span class="p">() <span class="line"> <span class="p">: <span class="n">Ok<span class="p">(<span class="n">package<span class="p">.<span class="n">ToODataPackage<span class="p">()); <span class="line"> <span class="p">} <span class="line"><span class="p">} </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code> Nach dem Login kopieren |
Standardmäßig weiß WebApi OData jedoch nicht, wie zusammengesetzte Schlüsselparameter an eine Aktion wie diese gebunden werden, da der Schlüssel aus mehreren Werten besteht.
Wir können dies beheben, indem wir eine neue Routing-Konvention erstellen, die den Inhalt der Klammer an unsere Routendatenkarte bindet:
<span class="line-number">1 <span class="line-number">2 <span class="line-number">3 <span class="line-number">4 <span class="line-number">5 <span class="line-number">6 <span class="line-number">7 <span class="line-number">8 <span class="line-number">9 <span class="line-number">10 <span class="line-number">11 <span class="line-number">12 <span class="line-number">13 <span class="line-number">14 <span class="line-number">15 <span class="line-number">16 <span class="line-number">17 <span class="line-number">18 <span class="line-number">19 <span class="line-number">20 <span class="line-number">21 <span class="line-number">22 <span class="line-number">23 <span class="line-number">24 <span class="line-number">25 <span class="line-number">26 <span class="line-number">27 <span class="line-number">28 <span class="line-number">29 <span class="line-number">30 <span class="line-number">31 <span class="line-number">32 <span class="line-number">33 <span class="line-number">34 <span class="line-number">35 <span class="line-number">36 <span class="line-number">37 <span class="line-number">38 <span class="line-number">39 <span class="line-number">40 <span class="line-number">41 <span class="line-number">42 <span class="line-number">43 <span class="line-number">44 <span class="line-number">45 <span class="line-number">46 <span class="line-number">47 <span class="line-number">48 <span class="line-number">49 <span class="line-number">50 <span class="line-number">51 <span class="line-number">52 </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span> Nach dem Login kopieren |
<code class="c#"><span class="line"><span class="k">public <span class="k">class <span class="nc">CompositeKeyRoutingConvention <span class="p">: <span class="n">IODataRoutingConvention <span class="line"><span class="p">{ <span class="line"> <span class="k">private <span class="k">readonly <span class="n">EntityRoutingConvention <span class="n">entityRoutingConvention <span class="p">= <span class="line"> <span class="k">new <span class="nf">EntityRoutingConvention<span class="p">(); <span class="line"> <span class="line"> <span class="k">public <span class="k">virtual <span class="kt">string <span class="nf">SelectController<span class="p">( <span class="line"> <span class="n">ODataPath <span class="n">odataPath<span class="p">, <span class="line"> <span class="n">HttpRequestMessage <span class="n">request<span class="p">) <span class="line"> <span class="p">{ <span class="line"> <span class="k">return <span class="n">entityRoutingConvention <span class="line"> <span class="p">.<span class="n">SelectController<span class="p">(<span class="n">odataPath<span class="p">, <span class="n">request<span class="p">); <span class="line"> <span class="p">} <span class="line"> <span class="line"> <span class="k">public <span class="k">virtual <span class="kt">string <span class="nf">SelectAction<span class="p">( <span class="line"> <span class="n">ODataPath <span class="n">odataPath<span class="p">, <span class="line"> <span class="n">HttpControllerContext <span class="n">controllerContext<span class="p">, <span class="line"> <span class="n">ILookup<span class="p"><<span class="kt">string<span class="p">, <span class="n">HttpActionDescriptor<span class="p">> <span class="n">actionMap<span class="p">) <span class="line"> <span class="p">{ <span class="line"> <span class="kt">var <span class="n">action <span class="p">= <span class="n">entityRoutingConvention <span class="line"> <span class="p">.<span class="n">SelectAction<span class="p">(<span class="n">odataPath<span class="p">, <span class="n">controllerContext<span class="p">, <span class="n">actionMap<span class="p">); <span class="line"> <span class="line"> <span class="k">if <span class="p">(<span class="n">action <span class="p">== <span class="k">null<span class="p">) <span class="line"> <span class="p">{ <span class="line"> <span class="k">return <span class="k">null<span class="p">; <span class="line"> <span class="p">} <span class="line"> <span class="line"> <span class="kt">var <span class="n">routeValues <span class="p">= <span class="n">controllerContext<span class="p">.<span class="n">RouteData<span class="p">.<span class="n">Values<span class="p">; <span class="line"> <span class="line"> <span class="kt">object <span class="k">value<span class="p">; <span class="line"> <span class="k">if <span class="p">(!<span class="n">routeValues<span class="p">.<span class="n">TryGetValue<span class="p">(<span class="n">ODataRouteConstants<span class="p">.<span class="n">Key<span class="p">, <span class="line"> <span class="k">out <span class="k">value<span class="p">)) <span class="line"> <span class="p">{ <span class="line"> <span class="k">return <span class="n">action<span class="p">; <span class="line"> <span class="p">} <span class="line"> <span class="line"> <span class="kt">var <span class="n">compoundKeyPairs <span class="p">= <span class="p">((<span class="kt">string<span class="p">)<span class="k">value<span class="p">).<span class="n">Split<span class="p">(<span class="sc">','<span class="p">); <span class="line"> <span class="line"> <span class="k">if <span class="p">(!<span class="n">compoundKeyPairs<span class="p">.<span class="n">Any<span class="p">()) <span class="line"> <span class="p">{ <span class="line"> <span class="k">return <span class="k">null<span class="p">; <span class="line"> <span class="p">} <span class="line"> <span class="line"> <span class="kt">var <span class="n">keyValues <span class="p">= <span class="n">compoundKeyPairs <span class="line"> <span class="p">.<span class="n">Select<span class="p">(<span class="n">kv <span class="p">=> <span class="n">kv<span class="p">.<span class="n">Split<span class="p">(<span class="sc">'='<span class="p">)) <span class="line"> <span class="p">.<span class="n">Select<span class="p">(<span class="n">kv <span class="p">=> <span class="line"> <span class="k">new <span class="n">KeyValuePair<span class="p"><<span class="kt">string<span class="p">, <span class="kt">object<span class="p">>(<span class="n">kv<span class="p">[<span class="m">0<span class="p">], <span class="n">kv<span class="p">[<span class="m">1<span class="p">])); <span class="line"> <span class="line"> <span class="n">routeValues<span class="p">.<span class="n">AddRange<span class="p">(<span class="n">keyValues<span class="p">); <span class="line"> <span class="line"> <span class="k">return <span class="n">action<span class="p">; <span class="line"> <span class="p">} <span class="line"><span class="p">} </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code> Nach dem Login kopieren |
Diese Klasse dekoriert einen Standard EntityRoutingConvention
und teilt den Rohschlüsselteil des URI in Schlüssel/Wert-Paare auf und fügt sie alle dem RouteValues-Wörterbuch hinzu.
Sobald dies erledigt ist, greift die Standardaktionsauflösung und findet die richtige aufzurufende Aktionsüberladung.
Diese Routing-Konvention wurde aus dem WebApi-ODataCompositeKeySample-Projekt übernommen.
Hier sehen wir einen weiteren Unterschied zwischen WebApi OData und WCF Data Services. In WCF Data Services übernimmt das Framework die Generierung einer Abfrage, die eine einzelne Instanz aus einem IQueryable
auswählt. Dies schränkt unsere Fähigkeit ein, die Suche nach einer Instanz anhand des Schlüssels anzupassen. In WebApi OData müssen wir explizit eine Überladung definieren, die eine Entitätsinstanz per Schlüssel abruft, was uns mehr Kontrolle darüber gibt, wie die Abfrage ausgeführt wird.
Diese Unterscheidung ist für die meisten Projekte möglicherweise nicht von Bedeutung, aber im Fall von NuGet.Lucene.Web ermöglicht sie eine Mirror-on-Demand-Funktion, bei der ein lokaler Feed ein Paket im Handumdrehen von einem anderen Server abrufen und hinzufügen kann das lokale Repository und senden Sie es dann an den Client zurück, als ob es schon immer dort gewesen wäre.
Um dies in WCF Data Services anzupassen, waren erhebliche Umstellungen erforderlich.
Das obige ist der detaillierte Inhalt vonZusammengesetzte Schlüssel mit WebApi OData. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!