EF Core 2.2,拥有的实体在层次结构中有多个时生成为另一个表

Ron*_*dau 5 entity-framework-core asp.net-core owned-types

我有一个带有Address标记的类[Owned]和人员层次结构的模型(人员、客户或员工,然后是更多的子类型等)。此层次结构的不同阶段有地址,并且所有地址最终都在一个表中,因为 EF Core 仅限于每个层次结构的表。我希望 address 中的所有属性在那个 person 表中出现多次(在任何子类型中每次提及一次)但是它根本没有出现!相反,我看到每个人的 FK 和一个单独的地址表。

EF Core 是否不支持同一类型的多个拥有成员?如果没有,我应该做什么?我没有任何可能干扰默认值的流畅 API/特定配置(新的空控制台项目,只有配置行是 .UseSQLServer(connectionstring)

示例代码如下:

public class SampleContext : DbContext
{
    public virtual DbSet<Address> Addresses { get; set; }
    public virtual DbSet<Customer> Customers { get; set; }
    public virtual DbSet<Employee> Employees { get; set; }
    public virtual DbSet<Person> Persons { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            optionsBuilder.UseSqlServer("my connection string here");
        }
        base.OnConfiguring(optionsBuilder);
    }
}
[Owned]
public class Address
{
    public int Id { get; set; }
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string AddressLine3 { get; set; }
    public string City { get; set; }
}

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
}

public class Employee : Person
{
    public Address Address { get; set; }
}

public class Customer : Person
{
    public Address DeliveryAddress { get; set; }
    public Address InvoicingAddress { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

预期Person表:

DeliveryAddressAddressLine1
DeliveryAddressAddressLine2
DeliveryAddressAddressLine3
DeliveryAddressAddressCity
InvoicingAddressAddressLine1
InvoicingAddressAddressLine2
InvoicingAddressAddressLine3
InvoicingAddressAddressCity
EmployeeAddressAddressLine1
EmployeeAddressAddressLine2
EmployeeAddressAddressLine3
EmployeeAddressAddressCity
Run Code Online (Sandbox Code Playgroud)

生成的Person表(+ 一个意外的Address表):

EmployeeAddressAddressId
DeliveryAddressAddressId
InvoicingAddressAddressId
Run Code Online (Sandbox Code Playgroud)

编辑:更新了问题,添加了上下文定义并注意到我有Addresses一个 DbSet 所以我认为这可能是原因,删除它会给我以下错误:

不能将表 'Person' 用于实体类型 'Customer.DeliveryAddress#Address',因为它用于实体类型 'Employee.Address#Address' 并且它们的主键之间没有关系。`

Tan*_*jel 5

根据 EF Core拥有的实体类型文档:

不支持包含拥有的实体类型的继承层次结构

您可以通过移动克服这个问题 public Address Address { get; set; }public Address DeliveryAddress { get; set; }public Address InvoicingAddress { get; set; }从导航属性EmployeeCustomer基类Person,如下所示:

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }

    public Address Address { get; set; }
    public Address DeliveryAddress { get; set; }
    public Address InvoicingAddress { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后使用 fluent API 进行配置以覆盖Navigation_OwnedEntityProperty拥有实体列名称的规则,如下所示:

modelBuilder.Entity<Person>().OwnsOne(p => p.Address,
    a =>
    {
         a.Property(p => p.AddressLine1).HasColumnName("EmployeeAddressLine1");
         a.Property(p => p.AddressLine2).HasColumnName("EmployeeAddressLine2");
         a.Property(p => p.AddressLine2).HasColumnName("EmployeeAddressLine3");
         a.Property(p => p.City).HasColumnName("EmployeeAddressCity");
    }).OwnsOne(p => p.DeliveryAddress,
    a =>
    {
        a.Property(p => p.AddressLine1).HasColumnName("DeliveryAddressLine1");
        a.Property(p => p.AddressLine2).HasColumnName("DeliveryAddressLine2");
        a.Property(p => p.AddressLine2).HasColumnName("DeliveryAddressLine3");
        a.Property(p => p.City).HasColumnName("DeliveryAddressCity");
   }).OwnsOne(p => p.InvoicingAddress,
   a =>
   {
        a.Property(p => p.AddressLine1).HasColumnName("InvoicingAddressLine1");
        a.Property(p => p.AddressLine2).HasColumnName("InvoicingAddressLine2");
        a.Property(p => p.AddressLine2).HasColumnName("InvoicingAddressLine3");
        a.Property(p => p.City).HasColumnName("InvoicingAddressCity");
   });
Run Code Online (Sandbox Code Playgroud)

现在,你,如果你不想动 public Address Address { get; set; }public Address DeliveryAddress { get; set; }以及public Address InvoicingAddress { get; set; }导航属性从EmployeeCustomer基类Person,那么你必须创建从每个地址类型不同的表如下:

modelBuilder.Entity<Employee>().OwnsOne(p => p.Address,
    a =>
    {
        a.ToTable("EmployeeAddresses");
    });

modelBuilder.Entity<Customer>().OwnsOne(p => p.DeliveryAddress,
    a =>
    {
        a.ToTable("DeliveryAddresses");
    }).OwnsOne(p => p.InvoicingAddress,
    a =>
    {
        a.ToTable("InvoicingAddresses");
    });
Run Code Online (Sandbox Code Playgroud)