本文属于 OData 系列

引言

在 OData 中,EDM(Entity Data Model) 代表“实体数据模型”,它是一种用于表示 Web API 中的结构化数据的格式。EDM 定义了可以由 OData 服务公开的数据类型、实体和关系。 EDM 也提供了一些规则来描述数据模型中的实体之间的关系,例如继承、关联和复合类型。EDM 是 OData 协议的核心组成部分之一,它允许客户端和服务器之间以一致的方式交换和操作数据。

EDM 与实体对象模型

我刚接触 EDM 时恰好是与 EF Core 一起使用,就非常不理解这个现象:明明已经在 EF Core 中已经定义了模型,为啥还需要单独配置一个 EDM?

其实,EDM 和实体框架(EF)Core 中的实体对象虽然都用于数据建模,但却是不同的概念:在 EF Core 中,实体对象表示数据库中的表或视图,而 EDM 定义了 OData 服务中的数据结构,包括实体、属性、导航属性等。可以理解实体对象是为数据库服务,而 EDM 是用于数据开放服务的

虽然 EDM 和 EF Core 中的实体对象都具有一些相似之处,例如它们都有属性和关系,甚至你也可以直接返回实体模型用提供给 OData 让其动态自动生成 EDM 模型(Non-ODM 模式),但是依然建议使用 EDM 模型,主要是有几个方面:

  1. 实体框架中的实体类可能包含与 OData 服务定义不同的属性。例如,实体框架中的实体类可能包含用于持久化和跟踪状态的属性,而这些属性可能并不需要在 OData 服务中公开。
  2. 实体框架中的实体类可能使用与 OData 服务定义不同的命名约定。例如,实体框架中的实体类可能使用 PascalCase(首字母大写)命名约定,而在 OData 服务中的 EDM 可以使用 camelCase(首字母小写)命名约定。
  3. 实体框架中的实体类可能包含与 OData 服务定义不同的数据结构。例如,联合主键的实现用于 OData 查询较为麻烦,可以配置 EDM 使得 OData 对外服务不使用联合主键。

EDM 配置

在配置 OData 时,我们需要在代码中提供 EDM 对象。

.AddRouteComponents(AuthorizeHelper.PREFIX, EdmHelper.GetEdmModels());

GetEdmModels 函数返回一个 IEdmModel 对象。

      public static IEdmModel GetEdmModels()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); var device = builder.EntitySet<DeviceInfo>("DeviceInfos").EntityType.HasKey(p => p.DeviceId);
device.Action("Upload");
builder.EnableLowerCamelCase();
return builder.GetEdmModel();
}

以上代码中对 DeviceInfo 类型定义了一个实体对象,其具有 DeviceId 作为主键,拥有一个名为 Upload 的 Action。并且对所有的 EDM 对象启用了 LowerCamelCase 支持。上面的感觉是挺简单的是吧,注意我们使用到了 ODataConventionModelBuilder 对象,这个对象帮助我们自动实现了很多配置内容。如果我们使用其他的方式就不那么简单了。实际上配置 EDM 总共有三种方式。

我一般只使用 Convention 的配置方法,因此这里引用官方网站的例子,详情请见 Introduction to the model builders - OData | Microsoft Learn

Explicit

如果模型通过 new EdmModel() 构建,那么构建的是无类型模型,相当于你不依赖现有的 CLR 类型凭空构建了一个模型。

public IEdmModel GetEdmModel()
{
EdmModel model = new EdmModel(); EdmEntityType customer = new EdmEntityType("WebApiDocNS", "Customer");
customer.AddKeys(customer.AddStructuralProperty("CustomerId", EdmPrimitiveTypeKind.Int32));
customer.AddStructuralProperty("Location", new EdmComplexTypeReference(address, isNullable: true));
model.AddElement(customer); EdmEntityType order = new EdmEntityType("WebApiDocNS", "Order");
order.AddKeys(order.AddStructuralProperty("OrderId", EdmPrimitiveTypeKind.Int32));
order.AddStructuralProperty("Token", EdmPrimitiveTypeKind.Guid);
model.AddElement(order); return model;
}

Non-convention

如果模型是依赖 new ODataModelBuilder() 构建,那么构建模型时可以依据现有的 CLR 对象进行构建,不过依然需要配置每一个属性、操作等。

public static IEdmModel GetEdmModel()
{
var builder = new ODataModelBuilder();
var customer = builder.EntityType<Customer>();
customer.HasKey(c => c.CustomerId);
customer.ComplexProperty(c => c.Location);
customer.HasMany(c => c.Orders); var order = builder.EntityType<Order>();
order.HasKey(o => o.OrderId);
order.Property(o => o.Token);
return builder.GetEdmModel();
}

相当于前一种方法已经有了很大改进,我们可以依赖现有的结构,而不再需要手动去命名了。

Convention

更进一步,我们可以使用惯例 ( Convention )方式,模型依赖 new ODataConventionModelBuilder () 构建,这个是代码最少的,整个模型的配置按照 OData RESTful 惯例实现。

      public static IEdmModel GetEdmModels()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); var device = builder.EntitySet<DeviceInfo>("DeviceInfos").EntityType;
return builder.GetEdmModel();
}

Convention 涉及的内容很多,有机会以后会详细解释惯例生成 EDM 这种模式。

常用 EDM 配置

EDM 配置项目繁多,我们常用的有:

  • 配置实体(主键)
var device = builder.EntitySet<DeviceInfo>("DeviceInfos").EntityType;
  • 配置(集合) Action
//对于实体上的Action
device.Action("Upload");
//对于集合上的Action
device.Collection.Action("Upload");
  • 配置(集合) Function
//对于实体上的Function
device.Function("Data").Returns<string>();
//对于集合上的Function
device.Collection.Function("Data").Returns<string>();

对 Function 以及 Action 的详细介绍,请期待后续文章。

访问 EDM 模型

OData 服务提供了 $metadata 终结点,可以从服务的根 URL 后添加 $metadata 来访问。例如以下是一个可以直接访问的 EDM 模型,以 XML 形式提供:

http://services.odata.org/TripPinRESTierService/$metadata

此外,也可以使用某些工具(如 Microsoft 的 OData Connected Service)来自动生成客户端代码,并从服务中获取元数据。这些工具通常会从服务的根 URL 下载 $metadata 文件,并将其解析为客户端代码。

OData WebAPI实践-OData与EDM的更多相关文章

  1. 让Asp.net mvc WebAPI 支持OData协议进行分页查询操作

    这是我在用Asp.net mvc WebAPI 支持 OData协议 做分页查询服务时的 个人拙笔. 代码已经开发到oschina上.有兴趣的朋友可以看看,欢迎大家指出不足之处. 看过了园子里的几篇关 ...

  2. 基于jQuery的ajax对WebApi和OData的封装

    基于jQuery的ajax对WebApi和OData的封装 WebApi 的使用带来了一个显著的特点,对type有一定的要求.一般ajax的type无非就是两种,GET和POST.如果用JSONP来跨 ...

  3. 让Asp.Net WebAPI支持OData查询,排序,过滤。

    让Asp.Net WebAPI支持OData后,就能支持在url中直接输入排序,过滤条件了. 一.创建Asp.Net WebAPI项目: 二.使用NuGet安装Asp.Net WebAPI 2.2和O ...

  4. jQuery的ajax对WebApi和OData的封装

    基于jQuery的ajax对WebApi和OData的封装 WebApi 的使用带来了一个显著的特点,对type有一定的要求.一般ajax的type无非就是两种,GET和POST.如果用JSONP来跨 ...

  5. 让Asp.Net WebAPI支持OData查询,排序,过滤。(转)

    出处:http://www.cnblogs.com/liuzhendong/p/4233380.html 让Asp.Net WebAPI支持OData后,就能支持在url中直接输入排序,过滤条件了. ...

  6. [转]OData/WebApi

    本文转自:https://github.com/OData/WebApi/tree/vNext OData Web API Introduction OData Web API (i.e., ASP. ...

  7. 快速搭建WebAPI(Odata+Code-First)附Odata条件查询表~

    Odata是什么? 开放数据协议(Open Data Protocol,缩写OData)是一种描述如何创建和访问Restful服务的OASIS标准.该标准由微软发起,前三个版本1.0.2.0.3.0都 ...

  8. Vue2.0 + Element-UI + WebAPI实践:简易个人记账系统

    最近正在学习Vue2.0相关知识,正好近期饿了么桌面端组件Element-UI发布,便动手做了一款简易个人记账系统,以达到实践及巩固目的. 1.开发环境 Win10 + VS2015 + Sqlser ...

  9. 【OData】使用Odata获取数据之后再次获取可能得不到最新的数据问题记录

    工作上遇到个问题是关于系统后台数据库更新了某数据后, 前台界面刷新显示的不是最新的数据.但是大约10分后再次刷新就能显示新的数据,或者重启IIS等web server host. 最开始认为可能是因为 ...

  10. webApi实践:开始WebApi 2

      1.学习步骤总结 学习网址:http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-you ...

随机推荐

  1. Java笔记第十三弹

    函数式接口 有且仅有一个抽象方法的接口 适用于Lambda使用的接口 @FunctionalInterface//表示函数式接口 函数式接口作为方法的参数 public class Main{ pub ...

  2. Javaweb学习笔记第七弹

    Maven依赖范围 对于Maven的安装配置等环境准备问题,可详细参考我的前几篇博客, 网址1:https://www.cnblogs.com/liuzijin/p/16654344.html 网址2 ...

  3. Android错误之--Error retrieving parent for item: No resource found that matches the given name 'Theme.A

    改正错误 (虽然内容较少,但是还是选择单独占用一篇) 这个错误,可以说是困扰了我好久,然后就看到可以改变一下使用的Android版本,改成Android 4.0,然后就去试了试,发现真的就好了耶! 就 ...

  4. JAVA异步编程之Callbacks与Futures模型

    JAVA异步编程之Callbacks与Futures模型 一:Callbacks模型 ​ 该模型的异步方法,在异步任务完成之后调用,主线程没有异步线程的结果.经典模型如Swing's EventLis ...

  5. 在进行程序国际化时(Locale)遇到的问题

    Java程序国际化-Question 为了使程序能够个根据不同的国家/语言环境来输出不同的内容,通常需要把将需要输出的内容定义在资源文件中. 而在创建资源文件的过程中难免会出现问题,我遇到了在创建资源 ...

  6. 全局唯一ID的实现方案

    为什么需要保证唯一ID? 在单机服务架构中,数据库的每一个业务表的主键ID都是允许自增的,但是在分布式服务架构的分库分表的设计,使得多个库或者多个表存储了相同的业务表,如果没有一个全局的唯一ID设计方 ...

  7. 1.HVV介绍

    HVV介绍 1.护网职责划分 红队:打点人员.攻击人员.社工人员 蓝队:监控人员.研判人员.溯源人员 2.护网需要具备的技能 红队: 外围打点能力.漏洞挖掘能力.漏洞分析能力.权限提升能力.权限维持能 ...

  8. 机器学习系列入门系列[七]:基于英雄联盟数据集的LightGBM的分类预测

    1. 机器学习系列入门系列[七]:基于英雄联盟数据集的LightGBM的分类预测 1.1 LightGBM原理简介 LightGBM是2017年由微软推出的可扩展机器学习系统,是微软旗下DMKT的一个 ...

  9. 前端ffmpeg实现视频剪切

    利用ffmpeg实现纯前端视频剪切 注意:在新版本Chrome浏览器中由于安全性问题,只能在https或localhost当中才能正常使用 1. 下载ffmpeg npm install @ffmpe ...

  10. Django笔记十四之统计总数、最新纪录和空值判断等功能

    本篇笔记将介绍一些 Django 查询中统计总数.最新纪录和空值判断等功能. count in_bulk latest.earliest first.last exists contains.icon ...