使用 ASP.NET Web API OData v4 中的复杂类型继承Complex Type Inheritance in OData v4 with ASP.NET Web API

by Microsoftby Microsoft

根据 OData v4规范,可以从另一种复杂类型继承的复杂类型。According to the OData v4 specification, a complex type can inherit from another complex type. (A复杂类型是结构化的类型没有键。)Web API OData 5.3 支持复杂类型继承。(A complex type is a structured type without a key.) Web API OData 5.3 supports complex type inheritance.

本主题演示如何生成实体数据模型 (EDM) 的复杂的继承类型。This topic shows how to build an entity data model (EDM) with complex inheritance types. 有关完整的源代码,请参阅OData 复杂类型继承示例For the complete source code, see OData Complex Type Inheritance Sample.

在本教程中使用的软件版本Software versions used in the tutorial

  • Web API OData 5.3Web API OData 5.3
  • OData v4OData v4

模型层次结构Model Hierarchy

为了说明复杂类型继承,我们将使用以下类层次结构。To illustrate complex type inheritance, we'll use the following class hierarchy.

Shape 是抽象的复杂类型。Shape is an abstract complex type. Rectangle``Triangle,并Circle复杂类型派生自Shape,和RoundRectangle派生RectangleRectangle, Triangle, and Circle are complex types derived from Shape, and RoundRectangle derives from Rectangle. Window 是一个实体类型,包含Shape实例。Window is an entity type and contains a Shape instance.

以下是定义这些类型的 CLR 类。Here are the CLR classes that define these types.

public class Window
{
    public int Id { get; set; }
    public string Title { get; set; }
    public Shape Shape { get; set; }
}

public abstract class Shape
{
    public bool HasBorder { get; set; }
    public Color Color { get; set; }
}

public class Rectangle : Shape
{
    public Point P1 { get; set; }
    public Point P2 { get; set; }
    public Point P3 { get; set; }
}

public class RoundRectangle : Rectangle
{
    public double Round { get; set; }
}

public class Triangle : Shape
{
    public Point LeftTop { get; set; }
    public int Height { get; set; }
    public int Weight { get; set; }
}

public class Circle : Shape
{
    public Point Center { get; set; }
    public int Radius { get; set; }
}

public class Point
{
    public int X { get; set; }
    public int Y { get; set; }
}

public enum Color
{
    Red,
    Blue,
    Green,
    Yellow
}

生成的 EDM 模型Build the EDM Model

若要创建 EDM,可以使用ODataConventionModelBuilder,,推断从 CLR 类型的继承关系。To create the EDM, you can use ODataConventionModelBuilder, which infers the inheritance relationships from the CLR types.

private IEdmModel GetEdmModel()
{
    ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
    builder.EntitySet<Window>("Windows");
    return builder.GetEdmModel();
}

您还可以构建 EDM 显式使用ODataModelBuilderYou can also build the EDM explicitly, using ODataModelBuilder. 这需要更多代码,但提供对 EDM 的更多控制。This takes more code, but gives you more control over the EDM.

private IEdmModel GetExplicitEdmModel()
{
  ODataModelBuilder builder = new ODataModelBuilder();

  EnumTypeConfiguration<Color> color = builder.EnumType<Color>();
  color.Member(Color.Red);
  color.Member(Color.Blue);
  color.Member(Color.Green);
  color.Member(Color.Yellow);

  ComplexTypeConfiguration<Point> point = builder.ComplexType<Point>();
  point.Property(c => c.X);
  point.Property(c => c.Y);

  ComplexTypeConfiguration<Shape> shape = builder.ComplexType<Shape>();
  shape.EnumProperty(c => c.Color);
  shape.Property(c => c.HasBorder);
  shape.Abstract();

  ComplexTypeConfiguration<Triangle> triangle = builder.ComplexType<Triangle>();
    triangle.ComplexProperty(c => c.P1);
    triangle.ComplexProperty(c => c.P2);
    triangle.ComplexProperty(c => c.P2);
    triangle.DerivesFrom<Shape>();

    ComplexTypeConfiguration<Rectangle> rectangle = builder.ComplexType<Rectangle>();
    rectangle.ComplexProperty(c => c.LeftTop);
    rectangle.Property(c => c.Height);
    rectangle.Property(c => c.Weight);
    rectangle.DerivesFrom<Shape>();

  ComplexTypeConfiguration<RoundRectangle> roundRectangle = builder.ComplexType<RoundRectangle>();
    roundRectangle.Property(c => c.Round);
    roundRectangle.DerivesFrom<Rectangle>();

    ComplexTypeConfiguration<Circle> circle = builder.ComplexType<Circle>();
    circle.ComplexProperty(c => c.Center);
    circle.Property(c => c.Radius);
    circle.DerivesFrom<Shape>();

    EntityTypeConfiguration<Window> window = builder.EntityType<Window>();
    window.HasKey(c => c.Id);
    window.Property(c => c.Title);
    window.ComplexProperty(c => c.Shape);

    builder.EntitySet<Window>("Windows");
    return builder.GetEdmModel();
}

这两个示例创建相同的 EDM 架构。These two examples create the same EDM schema.

元数据文档Metadata Document

下面是显示复杂类型继承的 OData 元数据文档。Here is the OData metadata document, showing complex type inheritance.

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
  <edmx:DataServices>
    <Schema Namespace="NS" xmlns="http://docs.oasis-open.org/odata/ns/edm">
      <EntityType Name="Window">
        <Key>
          <PropertyRef Name="Id" />
        </Key>
        <Property Name="Id" Type="Edm.Int32" Nullable="false" />
        <Property Name="Title" Type="Edm.String" />
        <Property Name="Shape" Type="BookStore.Shape" />
      </EntityType>
      <ComplexType Name="Shape" Abstract="true">
        <Property Name="HasBorder" Type="Edm.Boolean" Nullable="false" />
        <Property Name="Color" Type="BookStore.Color" Nullable="false" />
      </ComplexType>
      <ComplexType Name="Circle" BaseType="BookStore.Shape">
        <Property Name="Center" Type="BookStore.Point" />
        <Property Name="Radius" Type="Edm.Int32" Nullable="false" />
      </ComplexType>
      <ComplexType Name="Point">
        <Property Name="X" Type="Edm.Int32" Nullable="false" />
        <Property Name="Y" Type="Edm.Int32" Nullable="false" />
      </ComplexType>
      <ComplexType Name="Rectangle" BaseType="BookStore.Shape">
        <Property Name="LeftTop" Type="BookStore.Point" />
        <Property Name="Height" Type="Edm.Int32" Nullable="false" />
        <Property Name="Weight" Type="Edm.Int32" Nullable="false" />
      </ComplexType>
      <ComplexType Name="RoundRectangle" BaseType="BookStore.Rectangle">
        <Property Name="Round" Type="Edm.Double" Nullable="false" />
      </ComplexType>
      <ComplexType Name="Triangle" BaseType="BookStore.Shape">
        <Property Name="P1" Type="BookStore.Point" />
        <Property Name="P2" Type="BookStore.Point" />
        <Property Name="P3" Type="BookStore.Point" />
      </ComplexType>
      <EnumType Name="Color">
        <Member Name="Red" Value="0" />
        <Member Name="Blue" Value="1" />
        <Member Name="Green" Value="2" />
        <Member Name="Yellow" Value="3" />
      </EnumType>
    </Schema>
    <Schema Namespace="Default" xmlns="http://docs.oasis-open.org/odata/ns/edm">
      <EntityContainer Name="Container">
        <EntitySet Name="Windows" EntityType="BookStore.Window" />
      </EntityContainer>
    </Schema>
  </edmx:DataServices>
</edmx:Edmx>

从元数据文档中,您可以看到:From the metadata document, you can see that:

  • Shape复杂类型是抽象的。The Shape complex type is abstract.
  • RectangleTriangle,并Circle复杂类型具有基类型ShapeThe Rectangle, Triangle, and Circle complex type have the base type Shape.
  • RoundRectangle类型具有基类型RectangleThe RoundRectangle type has the base type Rectangle.

强制转换的复杂类型Casting Complex Types

现在支持对复杂类型强制转换。Casting on complex types is now supported. 例如,下面的查询强制转换ShapeRectangleFor example, the following query casts a Shape to a Rectangle.

GET ~/odata/Windows(1)/Shape/NS.Rectangle/LeftTop

下面是响应负载:Here's the response payload:

{ 
   "@odata.context":"http://localhost/odata/$metadata#Windows(1)/Shape/NS.Rectangle/LeftTop",
    "X":100,"Y":100
}