创建使用 Web API 2.2 OData v4 中的单一实例Create a Singleton in OData v4 Using Web API 2.2

通过 Zoe 卢奥语by Zoe Luo

传统上,如果它已封装在实体集内可以只访问实体。Traditionally, an entity could only be accessed if it were encapsulated inside an entity set. 但 OData v4 提供了两个附加选项,单独预测查询和包含关系,这两种支持 WebAPI 2.2。But OData v4 provides two additional options, Singleton and Containment, both of which WebAPI 2.2 supports.

本文介绍如何在 Web API 2.2 中的 OData 终结点中定义单一实例。This article shows how to define a singleton in an OData endpoint in Web API 2.2. 有关哪些单一实例以及如何从使用它受益的信息,请参阅使用单一实例定义特殊实体For information on what a singleton is and how you can benefit from using it, see Using a singleton to define your special entity. 若要创建 Web API OData V4 终结点,请参阅创建 OData v4 终结点使用 ASP.NET Web API 2.2To create an OData V4 endpoint in Web API, see Create an OData v4 Endpoint Using ASP.NET Web API 2.2.

使用以下数据模型在 Web API 项目中,我们将创建单一实例:We'll create a singleton in your Web API project using the following data model:

数据模型

名为单一实例Umbrella将根据类型来定义Company,和实体集命名Employees将基于类型定义EmployeeA singleton named Umbrella will be defined based on type Company, and an entity set named Employees will be defined based on type Employee.

可以从下载本教程中使用的解决方案CodePlexThe solution used in this tutorial can be downloaded from CodePlex.

定义数据模型Define the data model

  1. 定义 CLR 类型。Define the CLR types.

    /// <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 模型。Generate the EDM model based on the CLR types.

    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")告知模型生成器来创建名为单一实例UmbrellaEDM 模型中。Here, builder.Singleton<Company>("Umbrella") tells the model builder to create a singleton named Umbrella in the EDM model.

    生成的元数据将如下所示:The generated metadata will look like the following:

    <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>
    

    从元数据中我们可以看到,导航属性CompanyEmployees实体集绑定到单一实例UmbrellaFrom the metadata we can see that the navigation property Company in the Employees entity set is bound to the singleton Umbrella. 会自动完成绑定ODataConventionModelBuilder,因为仅Umbrella具有Company类型。The binding is done automatically by ODataConventionModelBuilder, since only Umbrella has the Company type. 如果在模型中存在任何多义性,可以使用HasSingletonBinding显式将一个导航属性绑定到单一实例;HasSingletonBinding具有相同的效果与使用SingletonCLR 类型定义中的属性:If there is any ambiguity in the model, you can use HasSingletonBinding to explicitly bind a navigation property to a singleton; HasSingletonBinding has the same effect as using the Singleton attribute in the CLR type definition:

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

定义单一实例控制器Define the singleton controller

单一实例控制器从与 EntitySet 控制器类似的继承ODataController,并单独控制器名称应为[singletonName]ControllerLike the EntitySet controller, the singleton controller inherits from ODataController, and the singleton controller name should be [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>()
        };
    } 
}

若要处理不同类型的请求,操作需要进行预定义,在控制器中。In order to handle different kinds of requests, actions are required to be pre-defined in the controller. 属性路由WebApi 2.2 中的默认情况下启用。Attribute routing is enabled by default in WebApi 2.2. 例如,若要定义要处理查询的操作RevenueCompany使用属性路由中,使用以下:For example, to define an action to handle querying Revenue from Company using attribute routing, use the following:

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

如果您不愿意来定义每个操作的属性,只需定义按照你的操作OData 路由约定If you are not willing to define attributes for each action, just define your actions following OData Routing Conventions. 由于密钥不需要查询单一实例,单独控制器中定义的操作是从 entityset 控制器中定义的操作略有不同。Since a key is not required for querying a singleton, the actions defined in the singleton controller are slightly different from actions defined in the entityset controller.

有关参考,下面列出了每个操作定义中的单一实例控制器中的方法签名。For reference, method signatures for every action definition in the singleton controller are listed below.

// 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()

基本上,这是所有需要在服务端上执行操作。Basically, this is all you need to do on the service side. 示例项目包含的所有解决方案和演示如何使用单一实例的 OData 客户端代码。The sample project contains all of the code for the solution and the OData client that shows how to use the singleton. 中的步骤生成客户端创建 OData v4 客户端应用The client is built by following the steps in Create an OData v4 Client App.

..

感谢您对 Leo Hu 这篇文章的原始内容。Thanks to Leo Hu for the original content of this article.