使用 Web API 2.2 在 OData v4 中创建单一实例

作者:Zoe Luo

传统上,仅当实体封装在实体集中时,才能访问该实体。 但 OData v4 提供了两个附加选项:单一实例和包含,这两个选项都支持 WebAPI 2.2。

本文介绍如何在 Web API 2.2 的 OData 终结点中定义单一实例。 有关什么是单一实例以及如何从使用它中获益的信息,请参阅 使用单一实例定义特殊实体。 若要在 Web API 中创建 OData V4 终结点,请参阅使用 ASP.NET Web API 2.2 创建 OData v4 终结点

我们将使用以下数据模型在 Web API 项目中创建单一实例:

数据模型

将基于类型 定义名为 Umbrella 的单一实例,并将基于类型 Employee定义名为 的Employees实体Company集。

定义数据模型

  1. 定义 CLR 类型。

    /// <summary> 
    /// Present the EntityType "Employee" 
    /// </summary> 
    public class Employee 
    {     
        public int ID { get; set; }     
        public string Name { get; set; }  
       
        [Singleton]     
        public Company Company { get; set; } 
    } 
    /// <summary> 
    /// Present company category, which is an enum type 
    /// </summary> 
    public enum CompanyCategory 
    { 
        IT = 0,     
        Communication = 1,     
        Electronics = 2,     
        Others = 3 
    } 
    /// <summary> 
    /// Present the EntityType "Company" 
    /// </summary> 
    public class Company 
    {
         public int ID { get; set; }
         public string Name { get; set; }
         public Int64 Revenue { get; set; }
         public CompanyCategory Category { get; set; }
         public List<Employee> Employees { get; set; } 
    }
    
  2. 基于 CLR 类型生成 EDM 模型。

    public static IEdmModel GetEdmModel() 
    { 
        ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
        builder.EntitySet<Employee>("Employees"); builder.Singleton<Company>("Umbrella");
        builder.Namespace = typeof(Company).Namespace;
        return builder.GetEdmModel(); 
    }
    

    此处, builder.Singleton<Company>("Umbrella") 告知模型生成器在 EDM 模型中创建名为 Umbrella 的单一实例。

    生成的元数据如下所示:

    <EntityContainer Name="Container"> 
      <EntitySet Name="Employees" EntityType="ODataSingletonSample.Employee"> 
        <NavigationPropertyBinding Path="Company" Target="Umbrella"/> 
      </EntitySet> 
      <Singleton Name="Umbrella" Type="ODataSingletonSample.Company"> 
        <NavigationPropertyBinding Path="Employees" Target="Employees"/> 
      </Singleton> 
    </EntityContainer>
    

    从元数据中可以看到,实体集中的Employees导航属性Company绑定到单一实例 Umbrella。 绑定由 ODataConventionModelBuilder自动完成,因为只有 Umbrella 类型 Company 。 如果模型中存在任何歧义,则可以使用 HasSingletonBinding 将导航属性显式绑定到单一实例; HasSingletonBinding 其效果与在 Singleton CLR 类型定义中使用 属性相同:

    EntitySetConfiguration<Employee> employeesConfiguration = 
        builder.EntitySet<Employee>("Employees"); 
    employeesConfiguration.HasSingletonBinding(c => c.Company, "Umbrella");
    

定义单一实例控制器

与 EntitySet 控制器一样,单一实例控制器继承自 ODataController,并且单一实例控制器名称应为 [singletonName]Controller

public class UmbrellaController : ODataController 
{
    public static Company Umbrella;
    static UmbrellaController()
    {
        InitData();
    }
    private static void InitData()
    {
        Umbrella = new Company()
        {
            ID = 1,
            Name = "Umbrella",
            Revenue = 1000,
            Category = CompanyCategory.Communication,
            Employees = new List<Employee>()
        };
    } 
}

为了处理不同类型的请求,需要在控制器中预定义操作。 WebApi 2.2 中默认启用属性路由。 例如,若要定义使用属性路由处理查询RevenueCompany的操作,请使用以下命令:

[ODataRoute("Umbrella/Revenue")] 
public IHttpActionResult GetCompanyRevenue() 
{
     return Ok(Umbrella.Revenue); 
}

如果不想为每个操作定义属性,只需按照 OData 路由约定定义操作即可。 由于查询单一实例不需要密钥,因此在单一实例控制器中定义的操作与实体集控制器中定义的操作略有不同。

下面列出了单一实例控制器中每个操作定义的方法签名以供参考。

// Get Singleton 
// ~/singleton 
public IHttpActionResult Get() 
public IHttpActionResult GetUmbrella() 

// Get Singleton 
// ~/singleton/cast 
public IHttpActionResult GetFromSubCompany() 
public IHttpActionResult GetUmbrellaFromSubCompany() 

// Get Singleton Property 
// ~/singleton/property  
public IHttpActionResult GetName() 
public IHttpActionResult GetNameFromCompany() 

// Get Singleton Navigation Property 
// ~/singleton/navigation  
public IHttpActionResult GetEmployees() 
public IHttpActionResult GetEmployeesFromCompany() 

// Update singleton by PUT 
// PUT ~/singleton 
public IHttpActionResult Put(Company newCompany) 
public IHttpActionResult PutUmbrella(Company newCompany) 

// Update singleton by Patch 
// PATCH ~/singleton 
public IHttpActionResult Patch(Delta<Company> item) 
public IHttpActionResult PatchUmbrella(Delta<Company> item) 

// Add navigation link to singleton 
// POST ~/singleton/navigation/$ref 
public IHttpActionResult CreateRef(string navigationProperty, [FromBody] Uri link) 

// Delete navigation link from singleton 
// DELETE ~/singleton/navigation/$ref?$id=~/relatedKey 
public IHttpActionResult DeleteRef(string relatedKey, string navigationProperty) 

// Add a new entity to singleton navigation property 
// POST ~/singleton/navigation 
public IHttpActionResult PostToEmployees([FromBody] Employee employee) 

// Call function bounded to singleton 
// GET ~/singleton/function() 
public IHttpActionResult GetEmployeesCount()

基本上,这是你需要在服务端执行的所有操作。 示例项目包含解决方案和 OData 客户端的所有代码,这些代码演示如何使用单一实例。 客户端是按照 创建 OData v4 客户端应用中的步骤生成的。

.

感谢胡利奥对本文的原创内容。