Maison > Article > développement back-end > Clés composites avec WebApi OData
本文转自:http://chris.eldredge.io/blog/2014/04/24/Composite-Keys/
Dans notre configuration de base, nous avons indiqué au constructeur de modèles que notre entité possède une clé composite composée d'un identifiant et d'une version :
<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> |
<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">7879bc2b6ec581464773019d50856563(<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></code> |
Cela suffit pour que notre flux OData affiche edit
et self
des liens pour chaque entité individuelle sous une forme telle que :
<code>http://localhost/odata/Packages(Id='Sample',Version='1.0.0') </code>
Mais si nous naviguons vers cette URL, au lieu d'obtenir uniquement cette entité par clé, nous récupérons l'ensemble de l'entité.
Pour obtenir le comportement correct, nous avons d'abord besoin d'un remplacement sur notre PackagesODataController qui obtient une instance d'entité individuelle par clé :
<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> |
<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">7879bc2b6ec581464773019d50856563 <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></code> |
Cependant, WebApi OData ne sait pas comment lier les paramètres de clé composite à une action comme celle-ci, car la clé est composée de plusieurs valeurs.
Nous pouvons résoudre ce problème en créant une nouvelle convention de routage qui lie les éléments entre parenthèses à notre carte de données d'itinéraire :
<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> |
<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">9a25b537e4c6dcc50cba8604f85ed988 <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">0f7bec63ba201452c985b787f98f17b8(<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></code> |
Cette classe décore un standard EntityRoutingConvention
et divise la partie clé brute de l'URI en paires clé/valeur et les ajoute toutes au dictionnaire routeValues.
Une fois cela fait, la résolution d'action standard entre en jeu et trouve la surcharge d'action correcte à invoquer.
Cette convention de routage a été adaptée du projet WebApi ODataCompositeKeySample.
Nous voyons ici une autre différence entre WebApi OData et WCF Data Services. Dans WCF Data Services, le framework gère la génération d'une requête qui sélectionne une seule instance à partir d'un IQueryable
. Cela limite notre capacité à personnaliser la façon dont la recherche d'une instance par clé est effectuée. Dans WebApi OData, nous devons définir explicitement une surcharge qui obtient une instance d'entité par clé, nous donnant plus de contrôle sur la façon dont la requête est exécutée.
Cette distinction n'a peut-être pas d'importance pour la plupart des projets, mais dans le cas de NuGet.Lucene.Web, elle permet une fonctionnalité de mise en miroir à la demande où un flux local peut récupérer un package à partir d'un autre serveur à la volée, l'ajouter à le référentiel local, puis renvoyez-le au client comme s'il était toujours là en premier lieu.
La personnalisation de cela dans WCF Data Services a nécessité d'importants retournements en arrière.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!