本文转自: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:

1
2
3
4
5
6
7
8
9
10
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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. Pointcut is malformed: Pointcut is not well-formed: expecting &#39;identifier&#39; at character position 0 ^
  2. HTML 代码复用实践 (静态页面公共部分提取复用)
  3. Atitit 拦截数据库异常的处理最佳实践
  4. java中如何生成可执行的jar文件
  5. JQuery获取元素的方法总结
  6. sqoop的增量导入(increment import)
  7. centOS安装openoffice
  8. MySQL 字段类型详解
  9. IOS 本地通知
  10. 此文件时入口文件index.php
  11. C#生成随机汉字
  12. eclipse创建一个文件夹
  13. GUI—ST_emWin移植
  14. Redis(转)
  15. 平台加载面板的方法$.loadPml
  16. Entity Framework Core的贴心:优雅处理带默认值的数据库字段
  17. VB播放声音
  18. 设置获取cookie,setCookie,getCookie
  19. js文件,同样的路径,拷贝过来的为什么不能访问
  20. EF5+MVC4系列(1) Podwerdesigner15.1设计数据库;PD中间表和EF实体模型设计器生成中间表的区别;EF5.0 表关系插入数据(一对多,多对多)

热门文章

  1. Kylin性能调优记——业务技术两手抓
  2. FasterRunner在Centos7.6服务器部署
  3. NOIP2012BLOCKADE贪心思想证明
  4. LOJ#6048. 「雅礼集训 2017 Day10」数列(线段树)
  5. Python 开发安卓Android及IOS应用库Kivy安装尝试
  6. Win10桌面图标无法拖动
  7. 版本控制(.git + .svn)
  8. 机器学习笔记(四)--sklearn数据集
  9. tomcat运行springboot项目war包
  10. Visual Studio各个版本对应关系