翼度科技»论坛 编程开发 .net 查看内容

OData WebAPI实践-OData与EDM

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
本文属于 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 模型,主要是有几个方面:

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

在配置 OData 时,我们需要在代码中提供 EDM 对象。
  1. .AddRouteComponents(AuthorizeHelper.PREFIX, EdmHelper.GetEdmModels());
复制代码
GetEdmModels 函数返回一个 IEdmModel 对象。
  1.       public static IEdmModel GetEdmModels()
  2.         {
  3.             ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
  4.             var device = builder.EntitySet<DeviceInfo>("DeviceInfos").EntityType.HasKey(p => p.DeviceId);
  5.                         device.Action("Upload");
  6.             builder.EnableLowerCamelCase();
  7.             return builder.GetEdmModel();
  8.         }
复制代码
以上代码中对 DeviceInfo 类型定义了一个实体对象,其具有 DeviceId 作为主键,拥有一个名为 Upload 的 Action。并且对所有的 EDM 对象启用了 LowerCamelCase 支持。上面的感觉是挺简单的是吧,注意我们使用到了 ODataConventionModelBuilder 对象,这个对象帮助我们自动实现了很多配置内容。如果我们使用其他的方式就不那么简单了。实际上配置 EDM 总共有三种方式。
我一般只使用 Convention 的配置方法,因此这里引用官方网站的例子,详情请见 Introduction to the model builders - OData | Microsoft Learn
Explicit

如果模型通过 new EdmModel() 构建,那么构建的是无类型模型,相当于你不依赖现有的 CLR 类型凭空构建了一个模型。
  1. public IEdmModel GetEdmModel()
  2. {
  3.     EdmModel model = new EdmModel();
  4.    
  5.         EdmEntityType customer = new EdmEntityType("WebApiDocNS", "Customer");
  6.         customer.AddKeys(customer.AddStructuralProperty("CustomerId", EdmPrimitiveTypeKind.Int32));
  7.         customer.AddStructuralProperty("Location", new EdmComplexTypeReference(address, isNullable: true));
  8.         model.AddElement(customer);
  9.        
  10.         EdmEntityType order = new EdmEntityType("WebApiDocNS", "Order");
  11.         order.AddKeys(order.AddStructuralProperty("OrderId", EdmPrimitiveTypeKind.Int32));
  12.         order.AddStructuralProperty("Token", EdmPrimitiveTypeKind.Guid);
  13.         model.AddElement(order);
  14.     return model;
  15. }
复制代码
Non-convention

如果模型是依赖 new ODataModelBuilder() 构建,那么构建模型时可以依据现有的 CLR 对象进行构建,不过依然需要配置每一个属性、操作等。
  1. public static IEdmModel GetEdmModel()
  2. {
  3.     var builder = new ODataModelBuilder();
  4.     var customer = builder.EntityType<Customer>();
  5. customer.HasKey(c => c.CustomerId);
  6. customer.ComplexProperty(c => c.Location);
  7. customer.HasMany(c => c.Orders);
  8.         var order = builder.EntityType<Order>();
  9. order.HasKey(o => o.OrderId);
  10. order.Property(o => o.Token);
  11.     return builder.GetEdmModel();
  12. }
复制代码
相当于前一种方法已经有了很大改进,我们可以依赖现有的结构,而不再需要手动去命名了。
Convention

更进一步,我们可以使用惯例 ( Convention )方式,模型依赖 new ODataConventionModelBuilder () 构建,这个是代码最少的,整个模型的配置按照 OData RESTful 惯例实现。
  1.       public static IEdmModel GetEdmModels()
  2.         {
  3.             ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
  4.             var device = builder.EntitySet<DeviceInfo>("DeviceInfos").EntityType;
  5.             return builder.GetEdmModel();
  6.         }
复制代码
Convention 涉及的内容很多,有机会以后会详细解释惯例生成 EDM 这种模式。
常用 EDM 配置

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

  • 配置实体(主键)
  1. var device = builder.EntitySet<DeviceInfo>("DeviceInfos").EntityType;
复制代码

  • 配置(集合) Action
  1. //对于实体上的Action
  2. device.Action("Upload");
  3. //对于集合上的Action
  4. device.Collection.Action("Upload");
复制代码

  • 配置(集合) Function
  1. //对于实体上的Function
  2. device.Function("Data").Returns<string>();
  3. //对于集合上的Function
  4. device.Collection.Function("Data").Returns<string>();
复制代码
对 Function 以及 Action 的详细介绍,请期待后续文章。
访问 EDM 模型

OData 服务提供了 $metadata 终结点,可以从服务的根 URL 后添加 $metadata 来访问。例如以下是一个可以直接访问的 EDM 模型,以 XML 形式提供:
  1. http://services.odata.org/TripPinRESTierService/$metadata
复制代码
此外,也可以使用某些工具(如 Microsoft 的 OData Connected Service)来自动生成客户端代码,并从服务中获取元数据。这些工具通常会从服务的根 URL 下载 $metadata 文件,并将其解析为客户端代码。

来源:https://www.cnblogs.com/podolski/archive/2023/05/11/17390887.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具