本文转自:http://chris.eldredge.io/blog/2014/04/24/Composite-Keys/

In our basic configuration we told the model builder that our entity has a composite key comprised of an ID and a version:

12345678910
public void MapDataServiceRoutes(HttpConfiguration config){    var builder = new ODataConventionModelBuilder();    var entity = builder.EntitySet<ODataPackage>("Packages");    entity.EntityType.HasKey(pkg => pkg.Id);    entity.EntityType.HasKey(pkg => pkg.Version);    // snip}

This is enough for our OData feed to render edit and self links for each individual entity in a form like:

http://localhost/odata/Packages(Id='Sample',Version='1.0.0')

But if we navigate to this URL, instead of getting just this one entity by key, we get back the entire entity set.

To get the correct behavior, first we need an override on our PackagesODataController that gets an individual entity instance by key:

1234567891011121314151617181920
public class PackagesODataController : ODataController{    public IMirroringPackageRepository Repository { get; set; }    public IQueryable<ODataPackage> Get()    {        return Repository.GetPackages().Select(p => p.ToODataPackage()).AsQueryable();    }    public IHttpActionResult Get(        [FromODataUri] string id,        [FromODataUri] string version)    {        var package = Repository.FindPackage(id, version);        return package == null          ? (IHttpActionResult)NotFound()          : Ok(package.ToODataPackage());    }}

However, out of the box WebApi OData doesn’t know how to bind composite key parameters to an action such as this, since the key is comprised of multiple values.

We can fix this by creating a new routing convention that binds the stuff inside the parenthesis to our route data map:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
public class CompositeKeyRoutingConvention : IODataRoutingConvention{    private readonly EntityRoutingConvention entityRoutingConvention =        new EntityRoutingConvention();    public virtual string SelectController(        ODataPath odataPath,        HttpRequestMessage request)    {        return entityRoutingConvention          .SelectController(odataPath, request);    }    public virtual string SelectAction(        ODataPath odataPath,        HttpControllerContext controllerContext,        ILookup<string, HttpActionDescriptor> actionMap)    {        var action = entityRoutingConvention            .SelectAction(odataPath, controllerContext, actionMap);        if (action == null)        {            return null;        }        var routeValues = controllerContext.RouteData.Values;        object value;        if (!routeValues.TryGetValue(ODataRouteConstants.Key,          out value))            {              return action;            }        var compoundKeyPairs = ((string)value).Split(',');        if (!compoundKeyPairs.Any())        {            return null;        }        var keyValues = compoundKeyPairs            .Select(kv => kv.Split('='))            .Select(kv =>              new KeyValuePair<string, object>(kv[0], kv[1]));        routeValues.AddRange(keyValues);        return action;    }}

This class decorates a standard EntityRoutingConvention and splits the raw key portion of the URI into key/value pairs and adds them all to the routeValues dictionary.

Once this is done the standard action resolution kicks in and finds the correct action overload to invoke.

This routing convention was adapted from the WebApi ODataCompositeKeySampleproject.

Here we see another difference between WebApi OData and WCF Data Services. In WCF Data Services, the framework handles generating a query that selects a single instance from an IQueryable. This limits our ability to customize how finding an instance by key is done. In WebApi OData, we have to explicitly define an overload that gets an entity instance by key, giving us more control over how the query is executed.

This distinction might not matter for most projects, but in the case of NuGet.Lucene.Web, it enables a mirror-on-demand capability where a local feed can fetch a package from another server on the fly, add it to the local repository, then send it back to the client as if it was always there in the first place.

To customize this in WCF Data Services required significant back flips.

 

Series Index

  1. Introduction
  2. Basic WebApi OData
  3. Composite Keys
  4. Default Streams

更多相关文章

  1. 解析PHP的基本文本输出
  2. php 读取文本文件
  3. 从文本文件中读取,然后决定是否要在php中禁用或启用按钮
  4. python 读写文本文件
  5. Python -在文本文件中添加日期戳
  6. 文本文件到字符串数组?
  7. 50分求关于执行SQL脚本文件的问题,在线等 解决了马上结贴。
  8. 请问用Java如何逐行的读取一个文本文件呀?我现在只能完整读取.
  9. 怎么在html,Javascript,vBscript中实现从网页上接收数据存入文本

随机推荐

  1. Android当中的MVP模式(六)View 层 Activity
  2. Android零基础入门第11节:简单几步带你飞,
  3. Android(安卓)提示Your project contains
  4. 中国iOS和Android设备激活量将超美国
  5. Android React Native使用原生UI组件
  6. Android_常驻进程(杀不死的进程)
  7. Android 脚本设计之 SL4A
  8. [笔记] android/iOS自动化测试神器Appium
  9. Android使用ViewFlipper实现图片切换功能
  10. 我的工具太少了之Android无限轮播图片,最