EF Core 2.2, собственные объекты, сгенерированные как другая таблица, когда несколько в иерархии - PullRequest
0 голосов
/ 04 февраля 2019

У меня есть модель с классом Address, помеченным [Owned], и иерархией людей (человек, клиент или сотрудник, затем еще больше подтипов и т. Д.).На разных этапах этой иерархии есть адреса, и все они заканчиваются в одной таблице, так как EF Core ограничен таблицей на иерархию.Я ожидал, что все атрибуты из адреса появятся несколько раз в этой таблице (один раз на упоминание в любом из подтипов), но это не так!Вместо этого я вижу 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; }
}

Ожидаемая Person таблица:

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

Сгенерированная Person таблица (+ неожиданная Address таблица):

EmployeeAddressAddressId
DeliveryAddressAddressId
InvoicingAddressAddressId

Редактировать: обновить вопрос, добавить определение контекстаи заметил, что у меня есть Addresses в качестве DbSet, поэтому я предполагаю, что это может быть причиной, удаление приводит к следующей ошибке:

Невозможно использовать таблицу «Персона» для типа сущности «Customer.DeliveryAddress #»Адрес », поскольку он используется для типа объекта« Employee.Address # Address », и между их первичными ключами нет никакой связи.

1 Ответ

0 голосов
/ 04 февраля 2019

Согласно EF Core Типы собственных объектов Документация:

Иерархии наследования, которые включают типы собственных объектов, не поддерживаются

Вы можете преодолеть этопроблема путем перемещения свойств навигации public Address Address { get; set; }, public Address DeliveryAddress { get; set; } и public Address InvoicingAddress { get; set; } из Employee и Customer в базовый класс 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; }
}

Затем настройте с помощью свободного 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");
   });

Теперь вы, если не хотите перемещать public Address Address { get; set; }, public Address DeliveryAddress { get; set; } и public Address InvoicingAddress { get; set; } свойства навигации из 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");
    });
...