具有继承功能的嵌套属性

时间:2019-05-07 21:12:16

标签: entity-framework inheritance asp.net-core database-design

我正在处理的

在线商店的实体订单具有成员 DeliveryDetails DeliveryDetails 的目的是包含特定于用户选择的递送方法的数据(例如,运输或从商店取货),而某些细节对于所有方法都是通用的(例如,名字,姓氏,电话号码) 。我在考虑使用继承的类似于以下内容的结构:

public class Order {
        // ....other props...
        public DeliveryMethodType DeliveryMethodType { get; set; }
        public DeliveryDetailsBase DeliveryDetails { get; set; }
}

    public class DeliveryDetailsBase
    {
        public int Id { get; set; }
        public string CustomerId { get; set; }
        public Order Order { get; set; }
        public int OrderId { get; set; }

        public string Firstname { get; set; }
        public string Lastname { get; set; }
        public string PhoneNumber { get; set; }
    }

    public class DeliveryDetailsShipping : DeliveryDetailsBase
    {
        public string Street { get; set; }
        public string Building { get; set; }
        public string Appartment { get; set; }
        public string PostalCode { get; set; }
        public string City { get; set; }
        public string Country { get; set; }
    }

    public class DeliveryDetailsPickupFromStore : DeliveryDetailsBase
    {
        public string StoreCode { get; set; }
    }

但是,我无法弄清楚如何根据客户选择的方法以及如何在ASP.Core上的EntityFramework中将 DeliveryDetails 道具分配给不同类型的交付方法详细信息。

我已经尝试过的解决方法:

->(1)。为所有传递方法创建“超级类”竞争道具,并仅在db中填充所选传递方法所需的那些(通过设置枚举 DeliveryMethodType 进行选择)。 OUTCOME :有效,但具有一张大而丑陋的表格,其中包含多个null。

->(2)。在订单中,创建道具 DeliveryDetails ,该道具又包含 DeliveryDetailsPickupFromStoreDATA DeliveryDetailsS​​hippingDATA OUTCOME :可以工作,但是有几个相关的表,并且有很多丑陋的代码检查枚举中的选定类型,为选定的传递方法实例化特定的子类,并将其他未使用的子类设置为空。

总结:还有其他更优雅,更可行的方法来组织此活动吗?

2 个答案:

答案 0 :(得分:0)

EF Core仅实现了Table Per Hierarchy (TPH)继承。

每种类型的表(TPT)为still an open ticket(未实现)。

每个具体类型(TPC)的表格也为still an open ticket(未实现)。

因此,如果TPH满足您的要求,则可以follow this guide。 基本上,将使用一个表,并使用名为Discriminator的额外列来确定记录对应的实现。

如果您刚开始使用Entity,我的建议是不要使用继承,而应将可空列用于根据类型而可能需要或不需要的数据。

答案 1 :(得分:0)

“还有其他更优雅,更可行的方式来组织这一活动吗?”保持简单,继承通常并不简单。 :)

一般而言,我选择继承而不是继承。使用起来更容易。给定需要传递到地址或商店的订单:

public class Order
{
  public DeliveryMethod DeliveryMethod { get; set; } = DeliveryMethod.None;

  public virtual OrderDeliveryAddress { get; set; } // should never be null.
  public virtual OrderDeliveryStore { get; set; } // not null if delivery mode = store.
}

public class Address
{
  public string Street { get; set; }
  public string Building { get; set; }
  public string Appartment { get; set; }
  public string PostalCode { get; set; }
  public string City { get; set; }
  public string Country { get; set; }   
}

public class OrderDeliveryAddress
{
  public virtual Order Order { get; set; }
  public virtual Address Address { get; set; }
}

public class Store
{
  public int StoreId { get; set; }
  public virtual Address { get; set; }
}

public class OrderDeliveryStore
{
  public virtual Order Order { get; set; }
  public virtual Store Store { get; set; }
}

其中DeliveryMethod是枚举。 {None = 0,ToAddress,ToStore}

下订单后,操作员可以选择将其交付到某个地址,选择客户的地址或输入新的地址记录;或者他们可以将其传递到商店,也可以将OrderDeliveryAddress设置为商店的地址。您可以在数据库/系统中建立检查,以确保交付方法和引用的OrderDeliveryAddress / OrderDeliveryStore的数据完整性同步,并引发可能出现的不匹配情况。

一个考虑因素是,在交付时,您可能希望根据客户地址克隆一个新的地址记录,或在订购时存储适用的地址,而不是通过ID引用其当前地址记录。原因是出于历史完整性。订单将在该时间点被发送到该地址,并且如果将来客户地址或商店地址发生更改,则过去的订单仍应显示该订单已交付的地址。