EF Core 2.2,拥有多个层次结构时,作为另一个表生成的拥有实体 [英] EF Core 2.2, owned entities generated as another table when multiple in hierarchy

查看:90
本文介绍了EF Core 2.2,拥有多个层次结构时,作为另一个表生成的拥有实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个模型,该模型具有标记为 [Owned] Address 类和人员层次结构(人员,客户或雇员,然后还有更多子类型,等等).在该层次结构的不同阶段存在地址,并且由于EF Core限于每个层次结构的表,所有地址最终都集中在一个表中.我希望所有来自address的属性在该人员表中出现多次(一次在任何子类型中提及),但根本不会出现!取而代之的是,我看到它们各自的FK和单独的地址表.

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

下面的示例代码:

 公共类SampleContext:DbContext{公共虚拟DbSet< Address>地址{get;放;}公共虚拟DbSet< Customer>客户{放;}公共虚拟DbSet< Employee>员工{得到;放;}公共虚拟DbSet< Person>人{放;}受保护的重写void OnConfiguring(DbContextOptionsBuilder optionsBuilder){如果(!optionsBuilder.IsConfigured){optionsBuilder.UseSqlServer(我的连接字符串在这里");}base.OnConfiguring(optionsBuilder);}}[所属]公共课地址{public int ID {get;放;}公共字符串AddressLine1 {get;放;}公共字符串AddressLine2 {get;放;}公共字符串AddressLine3 {get;放;}公共字符串City {get;放;}}公共类人{public int ID {get;放;}公共字符串FirstName {get;放;}公共字符串LastName {get;放;}公共DateTime DateOfBirth {get;放;}}公共班级员工:人{公共地址地址{get;放;}}公共类客户:人{公共地址DeliveryAddress {get;放;}公共地址InvoicingAddress {get;放;}} 

期望的人员表:

  DeliveryAddressAddressLine1DeliveryAddressAddressLine2DeliveryAddressAddressLine3DeliveryAddressAddressCityInvoicingAddressAddressLine1InvoicingAddressAddressLine2InvoicingAddressAddressLine3发票地址地址城市EmployeeAddressAddressLine1EmployeeAddressAddressLine2EmployeeAddressAddressLine3EmployeeAddressAddressCity 

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

  EmployeeAddressAddressIdDeliveryAddressAddressIdInvoicingAddressAddressId 

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

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

解决方案

根据EF Core

现在,如果您不想移动公共地址,地址{放;} 公共地址DeliveryAddress {get;放;} public Address InvoicingAddress {get;放;} 导航属性,从 Employee Customer 到基类 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");}); 

I have a model with a class Address marked [Owned] and a hierarchy of people (person, customer or employee, then even more subtypes etc). There are addresses at different stages of this hierarchy and all of it ends up in one table as EF Core is limited to table per hierarchy. I expected all the attributes from address to appear multiple times in that person table (once per mention in any of the subtypes) however it doesn't appear at all! Instead i see FK for each of them and a separate Address table.

Does EF Core not support multiple owned members of the same type? If not is there anything i should do? I don't have any fluent API / specific configuration that could interfere with the defaults (new empty console project, only config line is .UseSQLServer(connectionstring)

Sample code bellow :

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

Expected Person table :

DeliveryAddressAddressLine1
DeliveryAddressAddressLine2
DeliveryAddressAddressLine3
DeliveryAddressAddressCity
InvoicingAddressAddressLine1
InvoicingAddressAddressLine2
InvoicingAddressAddressLine3
InvoicingAddressAddressCity
EmployeeAddressAddressLine1
EmployeeAddressAddressLine2
EmployeeAddressAddressLine3
EmployeeAddressAddressCity

Generated Person table (+ an unexpected Address table):

EmployeeAddressAddressId
DeliveryAddressAddressId
InvoicingAddressAddressId

Edit : updated the question, added the context definition and noticed i had Addresses as a DbSet so i assume this may be the cause, removing it gives me the following error :

Cannot use table 'Person' for entity type 'Customer.DeliveryAddress#Address' since it is being used for entity type 'Employee.Address#Address' and there is no relationship between their primary keys.`

解决方案

According to EF Core Owned Entity Types documentation:

Inheritance hierarchies that include owned entity types are not supported

You can overcome this problem by moving public Address Address { get; set; }, public Address DeliveryAddress { get; set; } and public Address InvoicingAddress { get; set; } navigation properties from Employee and Customer to the base class Person as follows:

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

Then configure with fluent API to override the Navigation_OwnedEntityProperty rule for owned entity column name as follows:

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");
   });

Now you if you don't want to move public Address Address { get; set; }, public Address DeliveryAddress { get; set; } and public Address InvoicingAddress { get; set; } navigation properties from Employee and Customer to the base class Person then you have to create separate tables from each address types as follows:

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");
    });

这篇关于EF Core 2.2,拥有多个层次结构时,作为另一个表生成的拥有实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆