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

微软by Microsoft

根据 OData v4规范,复杂类型可以从另一种复杂类型继承。According to the OData v4 specification, a complex type can inherit from another complex type. 复杂类型是无键的结构化类型。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``TriangleCircle是从 派生Shape的复杂类型,并且RoundRectangle派生自RectangleRectangle, Triangle, and Circle are complex types derived from Shape, and RoundRectangle derives from Rectangle. Window是实体类型,包含实例ShapeWindow 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 LeftTop { get; set; }
    public int Height { get; set; }
    public int Weight { get; set; }
}

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

public class Triangle : Shape
{
    public Point P1 { get; set; }
    public Point P2 { get; set; }
    public Point P3 { 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();
}

您还可以使用ODataModelBuilder显式构建 EDM。You 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.
  • TriangleRectangle``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
}